使用依赖注入在工作线程中实例化对象

Instantiating an object in a worker thread with Dependency Injection

我的 objective 是 运行 并行线程中永无止境的进程。问题是,我不能只在新线程中实例化我的辅助服务,因为我在我的应用程序中使用了 DI。

根据我对 SO 的研究,我注意到很多人建议需要将抽象工厂注入到线程中以在并行线程中动态实例化线程安全对象。 1, 2

/// <summary>
/// Responsible for starting parallel long running worker threads
/// </summary>
public class ParallelWorkerStarter
{
    private readonly IQueueProcessorFactory _queueProcessorFactory;

    public ParallelWorkerStarter(IQueueProcessorFactory queueProcessorFactory)
    {
        _queueProcessorFactory = queueProcessorFactory;
    }

    public void StartQueueProcessorThread()
    {    
        queueProcessor = new Thread(
        () =>
        {
            _queueProcessorFactory.Create().ProcessQueue();
        })
        { Name = "QueueProcessor" };
        queueProcessor.Start();
    }
}

IQueueProcessorFactory 的抽象工厂如下所示:

/// <summary>
/// Abstract factory responsible for producing an <see cref="IQueueProcessor"/>
/// </summary>
/// <remarks>
///  This abstract factory is used to generate an <see cref="IQueueProcessor"/> In a seperate thread. 
///  Therefore, all of its dependencies also need to be dynamically generated
/// </remarks>
public interface IQueueProcessorFactory
{
    /// <summary>
    /// Dynamically creates ab <see cref="IQueueProcessor"/>
    /// </summary>
    /// <returns>
    /// The <see cref="IQueueProcessor"/>.
    /// </returns>
    IQueueProcessor Create();
}

现在,我的主要问题是,实现 IQueueProcessor 的具体 QueueProcessor 有 11 个依赖项(我知道 SRP 代码味道),每个依赖项本身有 5-6 个依赖项.

/// <inheritdoc />
public class QueueProcessorFactory : IQueueProcessorFactory
{
    private readonly IEventTriggerQueuedEventServiceFactory _qeueuedEventServiceFactory;

    private readonly ILoggerFactory _loggerFactory;

    private readonly IEventTriggerActionGroupLogServiceFactory _eventTriggerActionGroupLogServiceFactory;

    private readonly IExceptionLogServiceFactory _exceptionLogServiceFactory;

    private readonly IEventTriggerServiceFactory _eventTriggerServiceFactory;

    private readonly IConditionServiceFactory _conditionServiceFactory;

    private readonly IEventTriggerActionServiceFactory _eventTriggerActionServiceFactory;

    private readonly IEngineEnabledCheckerFactory _engineEnabledCheckerFactory;

    private readonly IEventTriggerScheduleSetServiceFactory _eventTriggerScheduleSetServiceFactory;

    private readonly IEventTriggerActionResultServiceFactory _eventTriggerActionResultServiceFactory;

    private readonly IWorkflowExceptionHandlerFactory _workflowExceptionHandlerFactory;

    public QueueProcessorFactory(
        IEventTriggerQueuedEventServiceFactory qeueuedEventServiceFactory,
        ILoggerFactory loggerFactory,
        IEventTriggerActionGroupLogServiceFactory eventTriggerActionGroupLogServiceFactory,
        IExceptionLogServiceFactory exceptionLogServiceFactory,
        IEventTriggerServiceFactory eventTriggerServiceFactory,
        IConditionServiceFactory conditionServiceFactory,
        IEventTriggerActionServiceFactory eventTriggerActionServiceFactory,
        IEngineEnabledCheckerFactory engineEnabledCheckerFactory,
        IEventTriggerScheduleSetServiceFactory eventTriggerScheduleSetServiceFactory,
        IEventTriggerActionResultServiceFactory eventTriggerActionResultServiceFactory,
        IWorkflowExceptionHandlerFactory workflowExceptionHandlerFactory)
    {
        _qeueuedEventServiceFactory = qeueuedEventServiceFactory;
        _loggerFactory = loggerFactory;
        _eventTriggerActionGroupLogServiceFactory = eventTriggerActionGroupLogServiceFactory;
        _exceptionLogServiceFactory = exceptionLogServiceFactory;
        _eventTriggerServiceFactory = eventTriggerServiceFactory;
        _conditionServiceFactory = conditionServiceFactory;
        _eventTriggerActionServiceFactory = eventTriggerActionServiceFactory;
        _engineEnabledCheckerFactory = engineEnabledCheckerFactory;
        _eventTriggerScheduleSetServiceFactory = eventTriggerScheduleSetServiceFactory;
        _eventTriggerActionResultServiceFactory = eventTriggerActionResultServiceFactory;
        _workflowExceptionHandlerFactory = workflowExceptionHandlerFactory;
    }

    /// <inheritdoc />
    public IQueueProcessor Create()
    {
        return new QueueProcessor(
            _qeueuedEventServiceFactory.Create(),
            _loggerFactory.Create(),
            _eventTriggerActionGroupLogServiceFactory.Create(),
            _exceptionLogServiceFactory.Create(),
            _eventTriggerServiceFactory.Create(),
            _conditionServiceFactory.Create(),
            _eventTriggerActionServiceFactory.Create(),
            _engineEnabledCheckerFactory.Create(),
            _eventTriggerScheduleSetServiceFactory.Create(),
            _eventTriggerActionResultServiceFactory.Create(),
            _workflowExceptionHandlerFactory.Create());
    }
}

这是否意味着我需要 ~60 多个抽象工厂才能在工作线程中实例化我的 IQueueProcessor?这听起来像一场噩梦!有没有更好的方法或更有效的方法来实现这一点?

Does this mean I need ~60+ abstract factories in order to instantiate my IQueueProcessor in a worker thread?

最坏的情况下,可能需要这样做。当所有依赖项都必须具有 Transient 生命周期时,可能会发生这种情况 - 例如,当它们不是线程安全的时。

然而,在最好的情况下,所有这些依赖项都可以具有单例生命周期,这可能适用于线程安全的依赖项。在那种情况下,不需要个内部工厂:

public class QueueProcessorFactory : IQueueProcessorFactory
{
    private readonly IEventTriggerQueuedEventService _qeueuedEventService;    
    private readonly ILogger _logger;    
    private readonly IEventTriggerActionGroupLogService _eventTriggerActionGroupLogService;
    // etc...

    public QueueProcessorFactory(
        IEventTriggerQueuedEventService qeueuedEventService,
        ILogger logger,
        IEventTriggerActionGroupLogService eventTriggerActionGroupLogService,
        /* etc... */)
    {
        _qeueuedEventService = qeueuedEventService;
        _logger = logger;
        _eventTriggerActionGroupLogService = eventTriggerActionGroupLogService;
        // etc...
    }

    public IQueueProcessor Create()
    {
        return new QueueProcessor(
            _qeueuedEventService,
            _logger,
            _eventTriggerActionGroupLogService,
            /* etc... */);
    }
}

实际上,您可能需要混合一些瞬态依赖项(这需要工厂)和一些单例依赖项。

如果您最终需要数十个工厂,您可以考虑使用 DI 容器。其中一些可以自动生成工厂接口的实现——您只需提供它们必须实现的接口。

此外,您不必为每个依赖项定义接口,但可以考虑使用通用接口,例如:

public interface IFactory<T>
{
    T Create();
}

同样,一些 DI 容器支持这样的工厂。您也可以考虑完全放弃接口,只使用像 Func<T>.

这样的委托

不过,除非情况特殊,否则我不推荐DI Container,而是赞同Pure DI。当您使用 DI 容器时,您会失去编译时安全性,我倾向于认为这是不值得的权衡;毕竟,编程的瓶颈很少是你的打字速度。