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

C# 面对winforms和其他生成的代码时的IoC/DI,c#,winforms,dependency-injection,code-generation,inversion-of-control,C#,Winforms,Dependency Injection,Code Generation,Inversion Of Control,当使用依赖项注入(DI)和控制反转(IoC)时,对象通常会有一个构造函数,该构造函数接受对象正常运行所需的依赖项集 例如,如果我有一个表单,它需要一个服务来填充一个组合框,您可能会看到如下内容: // my files public interface IDataService { IList<MyData> GetData(); } public interface IComboDataService { IList<MyComboData> GetC

当使用依赖项注入(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容器自动注入所有依赖项

一种解决方案是将每个子组件的依赖项传递到
PopulatedForm
,即使它可能不直接需要它们,例如使用
UserCreatedComboBox
所需的
IComboDataService
。然后,我有责任确保依赖关系是通过各种属性或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>();
        }
    }
}
公共类UserCreatedComboBox{
私有IComboDataService comboDataService;
公共用户CreatedComboBox(){
如果(!DesignMode&&IoC.Instance!=null){
comboDataService=Ioc.Instance.Resolve();
}
}
}

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

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


在您的两个解决方案中,我不喜欢第二个,尤其是因为在代码中引用了IoC容器,这在我看来很糟糕。

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

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


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

Re:引用IoC容器-我完全同意。我开始认为,正如您所提到的,一个设计需要的不仅仅是UI代码中的表示模型,它将在可测试性和良好的关注点分离方面受到影响。
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>();
        }
    }
}