【问题标题】:IoC/DI in the face of winforms and other generated code面对winforms和其他生成代码时的IoC/DI
【发布时间】:2011-06-25 20:48:44
【问题描述】:

在使用依赖注入 (DI) 和控制反转 (IoC) 时,对象通常会有一个构造函数,该构造函数接受对象正常运行所需的一组依赖项。

例如,如果我有一个需要服务来填充组合框的表单,您可能会看到如下内容:

// my files
public interface IDataService {
    IList<MyData> GetData();
}

public interface IComboDataService {
    IList<MyComboData> GetComboData();
}

public partial class PopulatedForm : BaseForm {
    private IDataService service;
    public PopulatedForm(IDataService service) {
        //...
        InitializeComponent();
    }
}

这在顶层可以正常工作,我只是使用我的 IoC 容器来解决依赖关系:

var form = ioc.Resolve<PopulatedForm>();

但是面对生成的代码,这变得更加困难。在 winforms 中,生成了组成部分类的其余部分的第二个文件。此文件引用其他组件,例如自定义控件,并使用无参数构造函数来创建此类控件:

// generated file: PopulatedForm.Designer.cs
public partial class PopulatedForm {
    private void InitializeComponent() {
        this.customComboBox = new UserCreatedComboBox();
        // customComboBox has an IComboDataService dependency
    }
}

由于这是生成的代码,我无法传入依赖项,也没有简单的方法让我的 IoC 容器自动注入所有依赖项。

一种解决方案是将每个子组件的依赖项传递给PopulatedForm,即使它可能并不直接需要它们,例如UserCreatedComboBox 所需的IComboDataService。然后,我有责任确保通过各种属性或 setter 方法提供依赖项。然后,我的PopulatedForm 构造函数可能如下所示:

public PopulatedForm(IDataService service, IComboDataService comboDataService) {
    this.service = service;
    InitializeComponent();
    this.customComboBox.ComboDataService = comboDataService;
}

另一种可能的解决方案是让无参数构造函数进行必要的解析:

public class UserCreatedComboBox {
    private IComboDataService comboDataService;
    public UserCreatedComboBox() {
        if (!DesignMode && IoC.Instance != null) {
            comboDataService = Ioc.Instance.Resolve<IComboDataService>();
        }
    }
}

这两种解决方案都不是特别好。面对生成的代码,有哪些模式和替代方案可以更有效地处理依赖注入?我希望看到通用解决方案(例如模式)以及特定于 C#、Winforms 和 Autofac 的解决方案。

【问题讨论】:

    标签: c# winforms dependency-injection code-generation inversion-of-control


    【解决方案1】:

    我相信这里没有灵丹妙药。在这种情况下,我将使用属性注入来保留无参数构造函数。此外,我个人不喜欢将服务注入 UI 类,我更喜欢在那里注入某种 Presenter。然后你有一个属性 Presenter 将由 IoC 容器设置,在这个属性的设置器中你将有你的初始化代码。

    在你的两个解决方案中,我不喜欢第二个,尤其是因为在你的代码中引用了 IoC 容器,这对 IMO 很不利。

    【讨论】:

    • Re: 引用 IoC 容器 - 我完全同意。我开始认为,正如您所提到的,在 UI 代码中需要的不仅仅是表示模型的设计将在可测试性和良好的关注点分离方面受到影响。
    【解决方案2】:

    我会说你的 UI,尤其是你的 UI 的子元素,不应该提供任何服务。

    很难判断这对您的应用程序是否可行,但 MVC 或 MVP 旨在避免这种需求。

    我会尝试重新设计,让控制器负责与服务交互,并且控制器为视图元素提供他们需要的一切,而不是让视图元素询问他们需要的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-15
      相关资源
      最近更新 更多