【问题标题】:IOC Container Circular Dependency Between Service and Factory服务和工厂之间的IOC容器循环依赖
【发布时间】:2021-05-08 05:10:39
【问题描述】:

我有以下类/接口:

public class DataExpressionViewModelFactory : IDataExpressionViewModelFactory
{
    private readonly IDataExpressionService DataExpressionService;

    public DataExpressionViewModelFactory(IDataExpressionService dataExpressionService)
    {
        DataExpressionService = dataExpressionService;
    }

    public DataExpressionViewModel Create(DatabaseTableColumn column)
    {
        return new DataExpressionViewModel(DataExpressionService, column);
    }
}

public class DataExpressionService : IDataExpressionService
{
    private readonly IDataExpressionViewModelFactory DataExpressionViewModelFactory;

    ...
}

使用 IOC 容器 (Microsoft.Extensions.DependencyInjection),它们之间存在循环依赖关系。 IDataExpressionViewModelFactory 需要 IDataExpressionService,反之亦然。

IDataExpressionViewModelFactory 创建DataExpressionViewModels,传入IDataExpressionServiceDataExpressionViewModels 使用 IDataExpressionService 来验证数据表达式字符串(用户输入)并从中进一步创建 DataExpressionViewModels,因为表达式可以相互嵌套(递归模型)。

有没有办法解决循环依赖?

【问题讨论】:

  • 要么使用 a) 如果你的 IoC 支持属性注入,b) 将你的接口包装在 Lazy 中以延迟服务解析,要么 c) 注入服务定位器并在需要时获取服务.在这两种情况下,解决方案都是将其中一个循环引用移出构造函数,并在实例化对象后将其解析,因此不再存在循环依赖。
  • 最好知道您使用的是什么具体的 IoC 容器库。它对于为您的容器提供正确答案很有用。
  • @aepot 我正在使用Microsoft.Extensions.DependencyInjection
  • 这听起来像是一个设计问题。要求我们解决循环冲突而不详细解释您为什么要这样创建它是很困难的。目前问题中的解释没有提供足够的细节,无法让我们提出替代方案。
  • @ChrisMack - 我还没有完全按照你的想法去做,但听起来很像你在混合视图模型和数据组件。这就是设计出错的地方。我当然会避免这样做。

标签: c# dependency-injection ioc-container circular-dependency


【解决方案1】:

在重构应用程序以使 IDataExpressionViewModel 成为模型 (IDataExpression) 并将服务拆分为“编写器”服务和“对象创建”服务之后,消除了循环依赖,我找到了一个解决方案:通过阅读 delegate factories 为原始设计工作。

我将委托用作其他实体的工厂,但实际上我为这个特定实体有两个构造函数,因此使用了工厂类。现在知道了委托工厂,我会说我原始设计中的代码味道(或其中之一)是在工厂本身内实例化服务。

使用委托工厂去除循环依赖:

委托工厂类

public delegate IDataExpressionViewModel CreateDataExpressionViewModel(DatabaseTableColumn column);
public delegate IDataExpressionViewModel CreateDataExpressionViewModelWithExpression(DatabaseTableColumn column, string expression);

public class DataExpressionViewModelDelegateFactory
{
    public readonly CreateDataExpressionViewModel;
    public readonly CreateDataExpressionViewModelWithExpression

    public DataExpressionViewModelDelegateFactory(
        CreateDataExpressionViewModel createDataExpressionViewModel,
        CreateDataExpressionViewModelWithExpression createDataExpressionViewModelWithExpression
    )
    {
        CreateDataExpressionViewModel = createDataExpressionViewModel;
        CreateDataExpressionViewModelWithExpression = createDataExpressionViewModelWithExpression;
    }
}

IOC 实现(在 App.xaml.cs 中)

services.AddTransient((provider) => new DataExpressionViewModelDelegateFactory(
    new CreateDataExpressionViewModel(
        (column) => new DataExpressionViewModel(
            provider.GetRequiredService<IDataExpressionService>(),
            column
        )
    ),
    new CreateDataExpressionViewModelWithExpression(
        (column, expression) => new DataExpressionViewModel(
            provider.GetRequiredService<IDataExpressionService>(),
            column,
            expression
        )
    )
));

委托工厂不依赖于服务,因为服务上的对象创建依赖关系在创建时由ServiceProvider解决,因此删除了依赖关系。

根据我链接的文章,如果需要大量委托并且变得过于繁琐,您还可以在工厂类中使用Func,而不是为每个方法创建特定的委托。

【讨论】:

    猜你喜欢
    • 2017-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    相关资源
    最近更新 更多