Ninject - 如何使用Parallel.ForEach循环中使用的类来IOC

NBP*_*C77 2 c# ninject inversion-of-control

我有一些代码如下所示.我是IoC和Ninject的新手,不知道如何将IOtherClass注入SomeService,以便Parallel.ForEach工作.我唯一的另一个猜测是将Parallel.ForEach移动到DoWork方法中?

谢谢你的帮助.

public class SomeService
{
    Parallel.Foreach(items, item =>
                       new OtherClass.DoWork(item);
}

public class OtherClass:IOtherClass
{
    public void DoWork()
    {...}
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 5

在应用依赖项注入时,您希望将相关对象的图形组合控件移动到名为Composition Root的应用程序中的单个位置.

要消除应用程序其余部分的复杂性,只有组合根应该知道要创建哪些实例以及如何创建它们.组合根是唯一了解对象图是如何构建的,并且它知道(或者至少在编写您应该知道的DI配置时)服务是否可以安全地相互依赖.这里应该发现线程安全问题.

实现本身不应该知道使用依赖是否安全; 它必须能够假设该依赖项在其运行的线程上使用是安全的.除了通常的瞬态和单身生活方式(其中,瞬态意味着创建一个新实例,其中单例意味着应用程序将只有该服务的一个实例),通常有其他生活方式具有线程亲和力.以Per Web Request的生活方式为例.

所以一般的建议是:

  • 让IoC容器为您解析所有对象,并且
  • 不要将服务从线程移动到线程.

SomeService从线程安全的角度来看,您的实现是正确的,因为每个线程都创建自己的新(瞬态)OtherClass实例.但是当OtherClass开始依赖自己时,这开始变得有问题.在这种情况下,您应该将该对象的创建移动到组合根目录.但是,如果您按照以下示例实现,则会出现问题:

public class SomeService
{
    private IOtherClass other;
    public SomeService(IOtherClass other)
    {
        this.other = other;
    }

    public void Operate(Items items)
    {   
        Parallel.Foreach(items, item => this.other.DoWork(item));
    }
}
Run Code Online (Sandbox Code Playgroud)

实现是有问题的,因为跨线程SomeService移动单个IOtherClass实例并假设它IOtherClass是线程安全的,这是只有组合根应该知道的知识.在整个应用程序中分散这些知识会增加复杂性.

在处理多线程代码时,每个线程都应该获得自己的对象图.这意味着在启动新线程时,您应该再次查询容器/内核以获取根对象并调用该对象.像这样:

public class SomeService
{
    private IItemProcessor processor;

    public SomeService(IItemProcessor processor)
    {
        this.processor = processor;
    }

    public void Operate(Items items)
    {
        this.processor.Process(items);
    }
}

public class ItemProcessor : IItemProcessor
{
    private IKernel container;

    public ItemProcessor(IKernel container)
    {
        this.container = container;
    }

    public void Process(Items items)
    {
        Parallel.Foreach(items, item =>
        {
            // request a new IOtherClass again on each thread.          
            var other = this.container.Get<IOtherClass>();
            other.DoWork(item);
        });    
    }
}
Run Code Online (Sandbox Code Playgroud)

这故意提取有关将这些项目处理成不同类别的机制.这允许保持业务逻辑SomeService并允许将ItemProcessor(仅应包含机制)移动到组合根中,从而防止使用服务定位器反模式.

本文将详细介绍在多线程应用程序中使用DI的更多信息.请注意,它是不同框架的文档,但一般建议是相同的.