當使用依賴注入(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