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

C#。如何在对象中注入依赖关系的多个实例?,c#,dependency-injection,C#,Dependency Injection,我有以下课程(部分课程): class SearchViewModel:BaseViewModel { 私有只读IDownloader\u downloader; 公共搜索视图模型(IDownloader-downloader) :底座(型号) { _下载器=下载器; } 私有void下载(对象发送方,DoWorkEventArgs e) { _下载(项目); } } 我使用IDownloader的构造函数注入,在多线程进入我的生活之前,它工作得很好 _downloader有一

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

class SearchViewModel:BaseViewModel
{        
私有只读IDownloader\u downloader;
公共搜索视图模型(IDownloader-downloader)
:底座(型号)
{
_下载器=下载器;
}
私有void下载(对象发送方,DoWorkEventArgs e)
{
_下载(项目);
}
}
我使用IDownloader的构造函数注入,在多线程进入我的生活之前,它工作得很好

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

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


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

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

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

private void Download(object sender, DoWorkEventArgs e)  
{  
    _downloaderFactory().Value.Download(item);  
}  
publicsearchViewModel(Func downloaderFactory)
:底座(型号)
{ 
_downloaderFactory=downloaderFactory;
} 
私有void下载(对象发送方,DoWorkEventArgs e)
{  
_downloaderFactory().Value.Download(项);
}  
Owned
是一个Autofac类,它表示不属于容器的T实例-解析它的类负责处理它。我不能100%确定Autofac是否会在每次调用
Func
时返回一个新的
IDownloader
实例,因此我会使用
Owned
来确定


一些IoC容器没有所有权/生命周期跟踪的概念,因此依赖于
Func
就足够了-你可以保证每次都会得到一个新实例。

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

.InThreadScope()
在您的绑定结束时

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

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

为什么不直接在工厂进行手工操作?这是一种非常常见的依赖注入代码模式

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);
    }
}
class SearchViewModel:BaseViewModel
{        
私有只读IDownloaderFactory\u工厂;
公共搜索视图模型(IDownloaderFactory工厂)
:底座(型号)
{
_工厂=工厂;
}
私有void下载(对象发送方,DoWorkEventArgs e)
{
_factory.Create().下载(项);
}
}

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

您所说的“多实例”是什么意思?您使用什么工具包/库进行DI?如果是Ninject,为什么不
kernel.Get()
例如,为
IDownloader
设置一个绑定?我认为这个答案对备选方案有相当好的描述-也许“多个实例”不是最好的标题。在调用Download()方法之前,我需要一个downloader类的新实例。谢谢,我使用Unity,我将寻找类似的功能。传递Func是一个非常好的解决方案。我以前从未见过它。但我认为在对象内部使用容器类会导致新的依赖关系。还有一个问题:您能否分享您的经验,在哪里以及如何更好地注册代表?再次感谢。这是一本很好的入门书,介绍了在Autofac中注册和解决依赖关系的各种方法:谢谢。我认为工厂是实现这一点的好方法,但我们并没有删除依赖项-我们将其移动到另一个地方。@YevhenMartynov依赖项必须存在-没有其他方法可以实例化<代码>新建或使用容器是您唯一的选择。这是“单一成分根”原则只会给你带来痛苦的情况之一。我建议稍微修改一下规则:允许容器在根目录和工厂中使用,就这样。谢谢你的回答。你能给我举个例子吗?
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);
    }
}