【发布时间】: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