2010-01-26 146 views
4

我想知道什麼,一般的建議是(屬性,接口,抽象類,或它們的組合)以下實現:屬性,接口或抽象類

/// <summary> 
    /// Loads class specific information into a list for serialization. The class must extend PlugIn. 
    /// The filenames parameter is passed from a FileDialog. 
    /// </summary> 
    /// <param name="filenames">Accepts any number of filenames with fully qualified paths.</param> 
    public static void ExtractPlugInData(params string[] filenames) 
    { 
    List<Type> l; 

    foreach (string f in filenames) 
    { 
    Assembly a = Assembly.LoadFrom(f); 
    // lambda expression selects any class within a library extending the abstract PlugIn class 
    l = a.GetTypes().Where(type => typeof(PlugIn).IsAssignableFrom(type)).ToList<Type>(); 

    if (l.Count > 0) 
      // write data to serializable class 
     WritePlugInData(f , l); 
    else 
     // throw exception 
     WriteLine("{0} :: No PlugIn Data Found" , a.FullName); 
      } 
    } 

我知道有優勢,每種方法的缺點。顯然,屬性需要一些反映(如抽象擴展和接口實現一樣)。一個抽象類需要我們唯一的基礎繼承,並且接口中的任何未來更改都可能會破壞任何現有的插件。所以,正如我所看到的那樣,這些都是缺點。

性能不是問題(除非有一些我沒有看到),因爲在提取一個合格的類中的任何反射只進行一次。要保存的關鍵數據是插件名稱(「MyPlugIn」),名稱空間(「SuperPlugIn.PlugInClass」)以及.dll的啓動路徑。現在,通過抽象PlugIn類,強制實現了屬性的擴展。如果我們實現一個接口(IPlugIn),這或多或少是相同的結果。

我們允許最終用戶編寫自定義插件。通過我們內部編寫的插件,可以很容易地爲我們的應用程序教授和執行一個必需的結構來實例化一個合格的類。但是,我也在考慮如果最終用戶發生重大變化,那麼困難或不便。

歡迎發表評論,建議和問題!

注意:要感謝喬恩斯基特在片段中的lambda表達式。 :)

編輯:我應該在這個旨在成爲獨立於平臺(即單聲道)開始所提到的。

UPDATE:基於優秀的建議,意見和下面的鏈接,屬性和接口的組合是最好的辦法。通過屬性可以加載程序集並相當安全地檢查所需的信息和實現,而無需實例化插件類/對象。在允許第三方或最終用戶創建自定義插件的情況下,這非常理想。我們可以檢查以確保合適的合同實施在屬性表明它應該是的地方。我們可以檢查所需的依賴關係和資源,並在任何實例之前提醒開發人員任何問題。

+0

我很確定它不會是一個接口。 – Jay 2010-01-26 03:44:32

+0

Aaronaught給出的許多參考文獻最終都使用了接口。令人驚訝的是,Mono.Addins(http://www.mono-project.com/Mono.Addins)去了屬性路由。 – IAbstract 2010-01-26 05:11:15

+0

的確如此,這就是爲什麼我最初用「幾乎」這個詞限定我的答案的原因。 ;)沒有*正確的*或*錯誤的*答案,你甚至可以將兩種方法結合起來(使用屬性來查找類,但仍然有實現插件接口)。 – Aaronaught 2010-01-26 05:41:13

回答

1

我可能傾向於使用屬性。用元數據擴展基類系統正是他們所需要的,並且說'這個類是插件'當然符合這個法案。

+0

@kyoryu:我開始傾向於這些屬性。請參閱我上面關於Mono.Addins的評論。我認爲這很有趣 - MS說接口,莫諾說屬性。 – IAbstract 2010-01-26 05:27:50

1

Assembly.GetTypes是一個非常昂貴的電話,我會盡可能避免它。 (應用程序啓動時間問題)

更快的方式做到這一點可能是(我沒有基準)的集級屬性,這會像這樣使用:

[assembly: PluginClass(typeof(MyPlugin), more info)] 

你可以調用GetCustomAttributesAssembly,這可能會比GetTypes快得多。

使用LINQ:

filenames.SelectMany(f => 
     Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true) 
     .Cast<PluginClassAttribute>() 
     .Select(a => a.PluginType) 
).ToList(); 
+0

如果發生其中一個異常,會發生什麼情況? – 2010-01-26 03:59:37

+0

這個Lambda很沉重...... – 2010-01-26 04:00:22

+0

如果加載程序集時發生異常,'ToList'調用將拋出,並且您將不會得到任何東西。如果你想用'catch'塊使用'foreach',請隨意。 – SLaks 2010-01-26 04:06:40

2

您希望您的終端用戶寫插件?我認爲這不是一個好主意,除非最終用戶是程序員。

我要保持我的回答很短這段時間,因爲這是一個prettybighonkin'dupe

編輯:單聲道,檢查出Mono.Addins

+0

道歉爲漂亮的大本生'愚蠢。我想我沒有搜索'插件'。 ;/Anyhoo ...我在看你提供的鏈接。 – IAbstract 2010-01-26 04:16:04

+0

@dboarman:不要擔心,我的意思是聽起來很輕鬆,我想它會變得很糟糕。我並不是在討好任何事情,只是想給出一個明確的理由給我簡要的回答,並讓你知道這是一個相當普遍的要求,並且有很多關於這個主題的優秀資源。 – Aaronaught 2010-01-26 04:23:59

+0

:)不用擔心......你有一些很好的參考。唯一的問題是MEF在.NET 4.0中可用,並且因爲我們正在瞄準Mono,所以這是不可能的。順便說一句,偉大的參考+1! – IAbstract 2010-01-26 05:16:55