2012-03-22 65 views
0

我認爲,如果沒有完整的體系結構更改,這可能是不可能的,但我有在運行時爲用戶公開可配置選項的類(插件)。在類實例化後的運行時使用依賴注入

該程序啓動時,用戶可以選擇使用各種插件,用戶面臨的選項,他們可以修改爲每個插件,用戶按下播放按鈕,這些配置選項讀取和關閉我們去。

當用戶選擇要使用的插件時,將創建該類的實例,以便它可以顯示該插件的可用選項。顯然,在正常情況下,當類實例化時,構造函數參數被傳入。在這種情況下,如果插件具有ILogger的構造函數參數,並且其具體類具有DirectoryPath的構造函數參數,但只有在用戶單擊播放後纔可讀取,我怎樣才能獲得我的國際奧委會容器通過它?

public class MyPlugin 
{ 
    private ILogger Logger; 
    private Dictionary<string, object> Properties = new Dictionary<string, object>(); 

    public MyPlugin(ILogger Logger) 
    { 
    this.Logger = Logger; 
    SetupProperties(); 
    } 

    private SetupProperties() 
    { 
    Properties.Add("LogDirectory","Please enter a directory"); 
    } 

    private void UserPressedPlay() 
    { 
    //We can now read the property values user has entered 
    //Now I want to instantiate FileLogger with the LogDirectory property 
    } 

    public DoSomething(string Data) 
    { 
    this.Logger.Write(Data); 
    } 
} 

public interface ILogger 
{ 
    void Write(string Data); 
} 

public FileLogger : ILogger 
{ 
    private string DirectoryPath; 

    public FileLogger(string Directory) 
    { 
    this.DirectoryPath = Directory; 
    } 

    public Write(string Data) 
    { 
     //Write to file 
    } 
} 
+3

我目前不使用IOC容器,因此我不會將其作爲答案發布,但我認爲您想要做的是傳入ILogger工廠而不是實際的ILogger。然後可以使用用戶的參數從UsrePressedPlay調用工廠以創建實際的Logger實例。 – 2012-03-22 21:01:14

+0

在不改變當前體系結構的情況下,我會在IoC中設置默認構造器設置 - 將設置目錄設置爲AppData \ Local \ Temp文件夾,然後在用戶單擊播放後重新初始化Logger界面。 雖然這是相當討厭的事情,並通過記錄器工廠提及500 - 內部服務器錯誤是一個好主意。 – 2012-03-22 21:14:46

+0

@ 500-InternalServerError所以你主張在這種情況下不使用IOC? – Jon 2012-03-22 21:18:20

回答

0

你想要做什麼是傳遞一個ILogger工廠,而不是實際的ILogger。然後可以從UserPressedPlay中調用該工廠的用戶參數來創建實際的Logger實例。

0

你可以一個DirectoryPath屬性添加到您的FileLogger後來intitialize它。

public FileLogger : ILogger 
{ 
    public string DirectoryPath { get; set; } 

    public Write(string Data) 
    { 
     if (DirectoryPath != null) { 
      // Write to file 
     } 
    } 
} 
+0

那麼不要使用IOC來實例化類? – Jon 2012-03-22 21:44:11

+0

一些IOC容器允許您定義在實例化後必須運行的附加規則或代碼。或者通過只讀屬性將插件中的記錄器公開。無論如何,您需要引用記錄器才能設置目錄路徑。如果你可以用IOC做到這一點,好的。 – 2012-03-22 22:08:05

+0

只讀屬性如何工作? – Jon 2012-03-22 22:09:45

0

您可以使用Expression.New來使用上述參數動態創建/調用您的構造函數。

Func<String, FileLogger> func = GetConsturctor<String, FileLogger>(); // Cache it somewhere. 

    FileLogger logger = func(@"C:\Loggerpath\"); // instantiate 

    static Func<TArg, TRes> GetConsturctor<TArg, TRes>() 
    { 
     Type resultType = typeof(TRes); 
     Type argType = typeof(TArg); 

     Type[] argumentArray = new Type[] { argType }; 
     ConstructorInfo constructor = resultType.GetConstructor(argumentArray); 

     ParameterExpression param = Expression.Parameter(argType); 
     Expression<Func<TArg, TRes>> result = Expression.Lambda<Func<TArg, TRes>>(
     Expression.New(constructor, param), param); 
     return result.Compile(); 
    } 
0

所以DI提供了很大的靈活性和較低的耦合度,但通常沒有必要。對於這種特殊情況,擔心如何添加它可能會過度。看起來你已經有了一個圖形用戶界面,它被配置爲匹配你用來配置它的FileLogger類,所以也許這裏的DI是矯枉過正的。你有今天插件使用的其他類型的​​嗎?如果是這樣,工廠選項可能是一個很好的選擇。基於提到的GUI,我懷疑只有一種類型的記錄器。在這種情況下,請不要在這裏使用DI掛機。如果你想弄清楚如何測試MyPlugin課程,並且不知道如何在沒有DI的情況下這樣做,那麼請告訴我,我會擴展這個答案以展示如何完成。

希望有幫助!

布蘭登

相關問題