C#。如何在对象中注入多个依赖项实例?

时间:2012-03-21 19:54:23

标签: c# dependency-injection

我有以下课程(部分内容):

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);
    }
}

我为IDownloader使用了构造函数注入,并且在多线程出现之前它已经运行良好。

_downloader有一个状态,我需要在单独的线程中运行_downloader.Download(item)(用户单击搜索结果页面上的下载按钮)。

目标:_downloader.Download(item)之前,应初始化_downloader的新实例。我可以使用_container.Resolve(IDownloader),但它会破坏组合根原则。

我已经创建了讨论最佳解决方案的问题,因为我认为直接初始化(new())或对容器的引用不是答案。

3 个答案:

答案 0 :(得分:6)

为什么不直接处理工厂?这是一种非常常见的依赖注入代码模式。

interface IDownloaderFactory 
{
  IDownloader Create();
}

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

然后将该工厂注入原始对象。

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);
    }
}

这样您就不依赖于特定于IOC容器的功能。

答案 1 :(得分:4)

实现显然取决于您使用的是哪个容器,但如果我需要在Autofac中执行类似的操作,我可能会这样做:

public SearchViewModel(Func<Owned<IDownloader>> downloaderFactory) 
    : base(model) 
{ 
    _downloaderFactory = downloaderFactory; 
} 

private void Download(object sender, DoWorkEventArgs e)  
{  
    _downloaderFactory().Value.Download(item);  
}  

Owned<T>是一个Autofac类,它表示不属于容器的T实例 - 解析它的类负责处理它。我不是100%确定Autofac是否会在每次调用IDownloader时向我返回Func<IDownloader>的新实例,因此我会使用Owned<T>来确定。

某些IoC容器没有所有权/生命周期跟踪的概念,因此依赖Func<IDownloader>就足够了 - 每次都可以保证获得新实例。

答案 2 :(得分:0)

我不确定我是否完全理解了这个问题但是如果你只想要每个线程一个新实例,你通常可以绑定指定的。例如,在Ninject中,您将指定

.InThreadScope()

在绑定结束时。

更新

您没有提供有关如何进行基本绑定的详细信息。但是在Ninject中我们假设您希望每次都将IDownloader绑定到MyDownloader,但是每个线程需要相同的MyDownloader实例,您可以使用

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