FROM#. How to insert multiple instances of dependencies inside an object?

I have the following class (part of it):

class SearchViewModel : BaseViewModel<SearchResultItem> { private readonly IDownloader _downloader; public SearchViewModel( IDownloader downloader) : base(model) { _downloader = downloader; } private void Download(object sender, DoWorkEventArgs e) { _downloader.Download(item); } } 

I used the constructor injection for IDownloader, and it worked fine before multithreading came into my life.

_downloader has state, and I need to run _downloader.Download (item) in separate threads (User clicks download buttons on the search results page).

Purpose: _downloader.Download(item) to _downloader.Download(item) , a new instance of _downloader should be initialized. I can use _container.Resolve(IDownloader) , but that would ruin the principle of root composition.

I created a question to discuss a better solution , because I believe that direct initialization (new ()) or a reference to the container is not the answer.

+6
source share
3 answers

Why not just run a factory? This is a very common pattern with code embedded in a dependency.

 interface IDownloaderFactory { IDownloader Create(); } class DownloaderFactory : IDownloaderFactory { IDownloader Create() { // either new it up here, or resolve from the container as you wish. } } 

Then enter factory in the source object.

 class SearchViewModel : BaseViewModel<SearchResultItem> { private readonly IDownloaderFactory _factory; public SearchViewModel( IDownloaderFactory factory) : base(model) { _factory = factory; } private void Download(object sender, DoWorkEventArgs e) { _factory.Create().Download(item); } } 

This way you are not dependent on a function specific to your IOC container.

+6
source

The implementation obviously depends on which container you use, but if I need to do something like this in Autofac, I would do this:

 public SearchViewModel(Func<Owned<IDownloader>> downloaderFactory) : base(model) { _downloaderFactory = downloaderFactory; } private void Download(object sender, DoWorkEventArgs e) { _downloaderFactory().Value.Download(item); } 

Owned<T> is an Autofac class that represents an instance of T that does not belong to the container - the class that allows it is responsible for removing it. I'm not 100% sure Autofac will give me a new instance of IDownloader every time I call Func<IDownloader> , so I would use Owned<T> to be sure.

Some IoC containers do not have a concept of tracking ownership / life cycle, so it is enough to depend on Func<IDownloader> - you are guaranteed to receive a new instance each time.

+4
source

I'm not sure I fully understood the question, but if you just need a new instance for the stream, you can associate it with the specified one. For example, in Ninject you must specify

 .InThreadScope() 

at the end of your binding.

Update

You did not provide details about how you did the database binding. But in Ninject, let's say that you want to bind IDownloader to MyDownloader every time, but you want the same instance of MyDownloader for the stream, you would use

 Bind<IDownloader>.To<MyDownloader>().InThreadScope(); 
0
source

Source: https://habr.com/ru/post/911348/


All Articles