IoC / DI面对winforms和其他生成的代码

时间:2011-02-11 22:13:58

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

当使用依赖注入(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中,生成组成其余部分类的第二个文件。此文件引用其他组件(如自定义控件),并使用no-args构造函数创建此类控件:

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

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

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

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

另一种可能的解决方案是让no-args构造函数执行必要的解决方案:

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

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

2 个答案:

答案 0 :(得分:6)

我相信这里没有银弹解决方案。在这种情况下,我会使用属性注入来保留无参数构造函数。另外我个人不喜欢将服务注入到UI类中,我更喜欢在那里注入某种类型的Presenter。然后你有一个属性Presenter,它将由IoC容器设置,在这个属性的setter中你将有你的初始化代码。

在你的两个解决方案中,我不喜欢第二个解决方案,特别是因为在代码中引用了IoC容器,这是不好的IMO。

答案 1 :(得分:3)

我想说你的UI,尤其是UI的子元素,不需要提供任何服务。

很难判断这对你的应用程序有多可行,但MVC或MVP是为了避免这种需要。

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