当使用依赖注入(DI)和控制反转(IoC)对象时,通常会有一个构造函数接受该对象正常运行所需的一组依赖项。面对winforms和其他生成代码的IoC/DI
举例来说,如果我有需要服务来填充组合框的形式,你可能会看到这样的事情:
// 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的解决方案。
Re:引用IoC容器 - 我绝对同意。我开始认为,正如你所暗示的那样,在UI代码中需要远远超过演示模型的设计将会受到可测试性和良好的问题分离的困扰。 – 2011-02-11 23:16:53