Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#. How to inject multiple instances of a dependency 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 constructor injection for IDownloader and it had worked fine before multithreading come to my life.

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

The goal: before _downloader.Download(item), a new instance of _downloader should be initialized. I can use _container.Resolve(IDownloader), but it would corrupt a Composition Root principle.

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

like image 957
Ievgen Martynov Avatar asked Mar 21 '12 19:03

Ievgen Martynov


2 Answers

Why not just handroll a factory? This is a very common pattern with dependency-injected code.

interface IDownloaderFactory 
{
  IDownloader Create();
}

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

Then inject that factory into your original 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're not dependent on a feature specific to your IOC container.

like image 132
Paul Phillips Avatar answered Oct 20 '22 16:10

Paul Phillips


The implementation obviously depends on which container you're using, but if I needed to do something like that in Autofac, I would probably 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 isn't owned by the container - the class that resolves it is responsible for disposing of it. I'm not 100% sure whether Autofac would return me a new instance of IDownloader with each call to a Func<IDownloader>, so I would use Owned<T> to be certain.

Some IoC containers don't have a concept of ownership/lifetime tracking, so taking a dependency on Func<IDownloader> would be enough - you'd be guaranteed to get a new instance each time.

like image 23
Matt Hamilton Avatar answered Oct 20 '22 17:10

Matt Hamilton