编程语言
首页 > 编程语言> > 正确在多线程应用程序中使用IOC(装饰器还是拦截器?)

正确在多线程应用程序中使用IOC(装饰器还是拦截器?)

作者:互联网

我正在使用非常相似的方法(例如this post中的方法)来进行项目.我将Unity用作DI-Framework,对此我还很新.
有一个JobController应该在新Task中启动n次注入服务.该代码看起来与Chads初始帖子中的代码几乎相同.

public class Controller
{
   IService _service;

   public Controller(IService service)
   {
       this._service = service;
   }

   public Action DoSomethingManyTimes()
   {
      for(int i =0; i < numberOfTimes; i++)
      {
         Task.Factory.StartNew(() =>
         {  
            _service.DoSomething();
         });
      }
   }
}

由于我的具体服务不是线程安全的,因此我遵循Marks的方法并实现了一个装饰器,该装饰器需要一个工厂来为每个具体的服务提供服务,就像Marks答案中的示例一样.我的课看起来像这样:

public ThreadSafeService1 : IService
{
   private readonly IServiceFactory factory;

   public ThreadSafeService1(IServiceFactory factory)
   {
       this.factory = factory;
   }

   public void DoSomething()
   {
       this.factory.Create().DoSomething();
   }
}

internal class Service1Factory : IServiceFactory
{
    public IService Create()
    {
        return new Service1();
    }
}

我有几个问题:

>代码不是DRY.我不想为我的每个服务编写ThreadSafeService-Decorator.而且我也不想为每个服务都拥有一个新的ServiceFactory.
>我的ServiceFactories的实现必须知道如何创建具体的服务,但是由于这些服务作为内部类存储在另一个程序集中,并且还具有必须注入的其他依赖项(对存储库等),因此我不确定在哪里使用Unity放置工厂以及如何创建具有所有依赖关系的具体服务.

看完Marks video之后,我尝试通过为Unity实现拦截器来解决第一个问题,如下所示:

internal class ThreadSafeServiceInterceptor : IInterceptionBehavior
{
    IServiceFactory serviceFactory;

    public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    {           
        serviceFactory.Create().Start();
        return getNext()(input, getNext);
    }

    ...
}

serviceFactory是通过构造函数注入的.除了我仍然没有找到问题2的好的解决方案这一事实之外,我怎么能告诉Unity必须将哪个具体的SessionFactory注入到我的拦截器中?这取决于启动的服务.目前,在我的应用程序中,我会执行以下操作:

var service = container.Resolve<IService>("Service1");
var controller = container.Resolve<JobController>(new ParameterOverride("service", service));

 controller.StartWork();

但是,当然服务无法解决. Unity无法注入serviceFactory,因为IServiceFactory有多个注册(针对我的每个服务).
除此之外,我的拦截器还将创建一个新的服务实例并启动它.之后,当调用getNext()()时,解析的服务也将启动并执行相同的操作.但是由于可能还有其他拦截器,我必须调用getNext().

所有这些让我觉得我走错了路.据我了解,拦截器应该处理跨领域的问题.但是使服务成为多线程不是跨领域的问题,对吗?

也许有人可以指出我正确的方向?

更新

@oleksii:
是的,没有.这是一个现实世界的项目,但我仍在起草体系结构.为此,我想要一个小的原型,并对照要求进行检查.我确实有几个服务,可以通过不同的UI来使用.
在这种情况下,UI是一个控制台应用程序,用于处理传入的作业.一项工作必须处理多个单元.为此,每个作业都会消耗一个具体的服务实现,但是由于服务被设计为仅处理一个单元.当然,我可以在JobController中执行类似的操作.

foreach(var unit in unitsToProcess)
{
   _service.DoSomethingWithUnit(unit);
}

但是我想并行处理几个单元.这就是为什么我认为我需要几个具体服务实例的原因.

解决方法:

我会做这样的事情

public class Controller
{
    Func<IService> _factory;

public Controller(Func<IService> factory)
{
   _factory = factory;
}

public Action DoSomethingManyTimes()
{
  for(int i =0; i < numberOfTimes; i++)
  {
     Task.Factory.StartNew(() =>
     {  
        _factory().DoSomething();
     });
  }
}
}

任何体面的DI容器都应该知道如何解析Func(我不使用Unity,默认情况下autofac会这样做).因此,您为服务注入一个工厂,然后每个任务将具有自己的服务实例.

我通常在单例存储库中使用这种方法,在该存储库中注入DbConnection的工厂或任何我需要的东西,然后每种方法将在不同的实例上工作并且不共享任何状态.

更新资料

服务工厂可以是一个抽象工厂,因此每个服务没有一个工厂,而所有服务都有一个工厂.所以也许像这样

Func<string,IService>

然后,您将Unity设置为仅注入工厂方法(来自服务工厂类).该工厂可以封装Unity以创建实际的服务

标签:multithreading,dependency-injection,c,ioc-container
来源: https://codeday.me/bug/20191120/2046399.html