2011-06-15 99 views
5

我正在構建一個可擴展應用程序,它將在運行時通過Assembly.LoadFile()加載其他程序集。那些額外的程序集將包含像WPF資源字典(皮膚等),普通資源(Resx)和/或插件類的東西。該程序集還可以不包含公共類,僅包含資源或資源字典。我正在尋找一種方法來識別程序集,諸如友好名稱(如「其他皮膚」或「集成瀏覽器」),程序集的功能類型(SkinsLibrary,SkinsLibrary | PluginLibrary等)和其他信息(如ConflictsWith(new [] {「SkinsLibrary」,「BrowserPlugin」)。.Net 4 - 在程序集中包含自定義信息

到目前爲止,我在命名程序集中使用了一個約定(*.Skins.*.dll等)。在每個程序集中,類僅僅是持有實際的(組裝寬)信息的自定義類屬性的佔位符,但感覺就像一個黑客攻擊。有沒有辦法處理這個問題的一些精簡,標準的方式?

我發展中央裝載機系統和我的團隊中的其他開發人員將開發這些額外的程序集,所以我想盡量減少約定和管道細節。

+0

如果已經定義了「默認」資源,資源文件(如果按名稱命名(name.lang.resx))應自動爲當前語言加載。框架爲你做。爲什麼你需要手動加載資源? – 2011-06-15 08:28:19

+0

因爲這些資源文件被編譯成一個程序集,並且有很多。例如,我有程序集Skin1和Skin2,並且配置表明應用程序使用Skin1,所以應用程序不應該自動加載它們。但是,應用程序必須知道Skin2的存在,以便用戶可以選擇它。 – 2011-06-15 08:33:00

+0

是否有可能以某種接口(ISkin?)的形式實現皮膚,所以你在一個DLL中編寫自己的實現,並向該DLL添加必要的資源?對於每個外觀,您將擁有一個裝配體,並且該裝配體所需的所有資源都是自動加載的。您只需要擔心兩個皮膚不會使用名稱相同的資源(通過在命名約定中添加皮膚名稱很容易防止)。 – 2011-06-15 08:37:13

回答

3

編輯:我更新了一些更詳細的信息的答案。

下面是一個例子,說明如何完成你想要做的事情。
首先爲您的不同類型的插件類型定義一個枚舉。

public enum AssemblyPluginType 
{ 
    Skins, 
    Browser 
} 

添加將用於描述插件(組件插件類型和潛在的衝突)兩種屬性。

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] 
public sealed class AssemblyPluginAttribute : Attribute 
{ 
    private readonly AssemblyPluginType _type; 

    public AssemblyPluginType PluginType 
    { 
     get { return _type; } 
    } 

    public AssemblyPluginAttribute(AssemblyPluginType type) 
    { 
     _type = type; 
    } 
} 

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] 
public sealed class AssemblyPluginConflictAttribute : Attribute 
{ 
    private readonly AssemblyPluginType[] _conflicts; 

    public AssemblyPluginType[] Conflicts 
    { 
     get { return _conflicts; } 
    } 

    public AssemblyPluginConflictAttribute(params AssemblyPluginType[] conflicts) 
    { 
     _conflicts = conflicts; 
    } 
} 

現在你可以將這些屬性添加到您的程序集。

只要它們位於命名空間之外,以下兩行就可以添加到程序集中的任何位置。我通常在AssemblyInfo.cs文件中放置裝配屬性,該文件可以在Properties文件夾中找到。

[assembly: AssemblyPluginAttribute(AssemblyPluginType.Browser)] 
[assembly: AssemblyPluginConflictAttribute(AssemblyPluginType.Skins, AssemblyPluginType.Browser)] 

現在你可以使用下面的代碼,以檢查特定屬性的組件:

using System; 
using System.Reflection; 

namespace ConsoleApplication 
{ 
    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      // Get the assembly we're going to check for attributes. 
      // You will want to load the assemblies you want to check at runtime. 
      Assembly assembly = typeof(Program).Assembly; 

      // Get all assembly plugin attributes that the assembly contains. 
      object[] attributes = assembly.GetCustomAttributes(typeof(AssemblyPluginAttribute), false); 
      if (attributes.Length == 1) 
      { 
       // Cast the attribute and get the assembly plugin type from it. 
       var attribute = attributes[0] as AssemblyPluginAttribute; 
       AssemblyPluginType pluginType = attribute.PluginType; 
      } 
     } 
    } 
} 
+0

謝謝,請你指出我應該在哪裏放置'[assembly:...]'屬性,以及如何查詢程序集的這些屬性? – 2011-06-15 12:07:35

+0

@Boris:我已經用更多的信息更新了答案,包括聲明裝配屬性的位置以及如何從裝配中查詢信息。 – Patrik 2011-06-16 16:12:05

2

我部分地獲得信息,但

您可以添加Custom AssemblyInfo Attributes,您可以通過訪問鏈接看..

+1

謝謝,這可能就是我正在尋找的東西,會嘗試。 – 2011-06-15 08:36:35

0

對於插件,我有MvcTurbine豐富的經驗(它可以與其他項目,不能使用只有mvc)。如果您在使用Ninject組合使用,並定義界面插件,即:

IPlugin{ 
    string Name {get;} 
    someResultType PerformAction(someArgType arg); 

} 

,並在你的插件DLL您通過實現從MvcTurbine IServiceRegistrator接口,那麼如果你把DLL在倉插件註冊實現IPlugin的目錄下,你的插件實現將被添加到傳入某個使用DI的類的構造函數並接收List的列表中,或者你可以手工從IOC容器中解析它。 它比手動加載你的組件和檢查他們的接口/實現等更清潔...

如果你有興趣在這,請問如果有什麼不清楚,我會詳細說明。