2012-05-07 5 views
1

Iveは、定義済みの物理ファイルパスからDLLを動的にロードするプラグインアーキテクチャをC#.NETに構築しました。私は現在、私はインターフェイスを使用しています... ...プラグインアーキテクチャのアセンブリを動的にロード

if(plugin is T) 
    // cache the assembly 

おそらくこれのようなものを使用してアセンブリ内のメンバー(インターフェース)を確認することが信頼できなくなって2つの場所でメモリ位置に既存のアセンブリの承知しています比較する名前、それからインスタンスをアクティブにします。インタフェースのIPlugin」は、サードパーティのアセンブリの多くは使用し非常に一般的なインタフェース名、(すなわちlog4netの、など)であるので、しかし、これはあまりにも制限があり

次のコードを取る(動作しないものである):

foreach (Type t in assembly.GetTypes()) 
{ 
    type = t; 

    if (!type.IsInterface) 
    { 
     var plugin = type.GetInterface(typeof(T).Name); 

     if (plugin != null) 
      if (plugin is T) 
      { 
       T p = (T)Activator.CreateInstance(type); 

       if (!this.Plugins.Select(sp => sp.Name).Contains(p.Name)) 
        this.Plugins.Add(p); 
      } 
    } 
} 

私の質問:動的に読み込まれたDLLがIPluginインターフェイスに一致するかどうかを確認する最も信頼性の高い方法は何ですか?

考えてみてください.IPluginの公開鍵トークンをハードコードして検証しますが、より正式な方法があるかどうかは疑問です。たとえば、IPlugin名や公開鍵トークンを偽装するアセンブリで潜在的なセキュリティホールが発生する可能性があると考えられます。ロードされたDLLがロードされているアセンブリのシグネチャと一致するかどうかをテストする良い方法があります。

もっと明快さが必要な場合は教えてください。

非常に感謝します!

答えて

1

使用IsAssignableFrom

var yourIPlugin = typeof(IPlugin); 
foreach (Type t in assembly.GetTypes()) 
{ 
    if (yourIPlugin.IsAssignableFrom(t)) 
    { 
      T p = (T)Activator.CreateInstance(t); 
      if (!this.Plugins.Select(sp => sp.Name).Contains(p.Name)) 
       this.Plugins.Add(p); 
    } 
} 

IsAssignableFromは別のタイプは、それから割り当てることができるかどうかを確認するためにタイプを使用しています。タイプの名前だけでなく、実際のタイプを完全に考慮します。したがって、アセンブリまたはその他のアセンブリにIPluginという名前の型が含まれていても、yourIPluginの型のみが見つかります。

2

私はそうのようにそれを解決:

public List<T> LoadPluginsFromPath<T>(string Path) {   
    List<T> results = new List<T>(); 

    DirectoryInfo Directory = new DirectoryInfo(Path); 
    if (!Directory.Exists) { 
     return results; // Nothing to do here 
    } 

    FileInfo[] files = Directory.GetFiles("*.dll"); 
    if (files != null && files.Length > 0) { 
     foreach (FileInfo fi in files) { 
      List<T> step = LoadPluginFromAssembly(fi.FullName); 
      if (step != null && step.Count > 0) { 
       results.AddRange(step); 
      } 
     } 
    } 

    return results; 
} 

private List<T> LoadPluginFromAssembly<T>(string Filename) { 
    List<T> results = new List<T>(); 

    Type pluginType = typeof(T); 

    Assembly assembly = Assembly.LoadFrom(Filename); 
    if (assembly == null) { 
     return results; 
    } 

    Type[] types = assembly.GetExportedTypes(); 
    foreach (Type t in types) { 

     if (!t.IsClass || t.IsNotPublic) { 
      continue; 
     } 

     if (pluginType.IsAssignableFrom(t)) { 
      T plugin = Activator.CreateInstance(t) as T; 
      if (plugin != null) { 
       results.Add(plugin); 
      } 
     } 

    } 

    return results; 
} 

私はそうのようにそれを呼び出す:アセンブリ内のすべての型を列挙する

List<MyPlugin> plugins = LoadPluginsFromPath<MyPlugin>("plugins"); 
1

Insteas、なぜあなたは、ファクトリクラスを定義していませんか?

"YourFramework.PluginTypeFactory"などのより適切な名前を持つファクトリクラスは、実際には名前の衝突の可能性を排除します。

さらに、Assembly.GetTypesfailとなる可能性があります。特定のアセンブリではひどく、バグのアセンブリには多くの時間がかかります。

1

私はあなたがそうであるように同じ問題を抱えているために起こった、いくつかの「プラグイン」が2回ロードされたと

IsAssignableFrom 

を使用した場合、.NET Frameworkが種類を解決することができませんでした、私はそれがハンドラを追加する解決AppDomainのAssemblyResolveイベントを取得し、現在のAppDomainのAssembliesコレクションに既に読み込まれている場合は、再度「Plugin」をロードしません。

いくつかのプラグインがお互いに依存し始め、Assemblyローダーがすでにロードされているときに同じアセンブリを何度も繰り返し読み込んでいたときに、ほとんどのことが起こりました。

あなたの問題を解決するのに役立つことを願って、それは確かに私を夢中にさせました!

関連する問題