16

當使用依賴注入(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的解決方案。

回答

6

我相信這裏沒有銀子彈解決方案。在這種情況下,我會使用屬性注入來留下無參數的構造函數。另外我個人不喜歡向UI類注入服務,我更喜歡在那裏注入某種主持人。然後你有一個屬性Presenter,它將由IoC容器設置,並且在這個屬性的setter中,你將有你的初始化代碼。

在你的兩個解決方案中,我不喜歡第二個解決方案,特別是因爲在你的代碼中引用了IoC容器,這是不好的IMO。

+0

Re:引用IoC容器 - 我絕對同意。我開始認爲,正如你所暗示的那樣,在UI代碼中需要遠遠超過演示模型的設計將會受到可測試性和良好的問題分離的困擾。 – 2011-02-11 23:16:53

3

我會說你的UI,尤其是你的UI的子元素,應該不需要提供任何服務。

很難判斷這對您的應用程序有多可行,但MVC或MVP旨在避免此需求。

我會嘗試重新設計,以便控制器負責與服務進行交互,並且該控制器給視圖元素提供他們需要的所有內容,而不是讓視圖元素詢問他們需要的內容。