2011-10-25 20 views
77

私はこのようなコードを使用して特定のインターフェイスを実装するタイプのためのアセンブリをスキャンしようとしている:Assembly.GetTypes()を呼び出すときにReflectionTypeLoadExceptionを防ぐ方法

public List<Type> FindTypesImplementing<T>(string assemblyPath) 
{ 
    var matchingTypes = new List<Type>(); 
    var asm = Assembly.LoadFrom(assemblyPath); 
    foreach (var t in asm.GetTypes()) 
    { 
     if (typeof(T).IsAssignableFrom(t)) 
      matchingTypes.Add(t); 
    } 
    return matchingTypes; 
} 

私の問題は、私はReflectionTypeLoadExceptionを得ることであり、場合によってはasm.GetTypes()を呼び出すと、例えばアセンブリに現在使用できないアセンブリを参照する型が含まれている場合

私の場合は、問題の原因となるタイプには興味がありません。私が探している型には、使用できないアセンブリは必要ありません。

問題は、例外を引き起こすタイプをスキップ/無視しても、アセンブリに含まれる他のタイプを処理することができますか?

+1

あなたが探しているものよりもはるかに多くの書き換えがありますが、MEFは同様の機能を提供します。各クラスに、実装するインタフェースを指定する[Export]タグを付けてください。その後、その時点で興味のあるインタフェースだけをインポートできます。 –

+0

@Drew、ご意見ありがとうございます。私はMEFの使用について考えていましたが、もう少し安価なソリューションがあるかどうかを見たいと思っていました。 – M4N

+0

プラグインクラスファクトリによく知られた名前を付けるだけで、Activator.CreateInstance()を直接使用することができます。これは簡単な回避策です。それでもアセンブリの解決の問題のためにこの例外が発生した場合は、おそらく後でそれを取得するでしょう。 –

答えて

101

一つかなり厄介な方法は、次のようになります。

Type[] types; 
try 
{ 
    types = asm.GetTypes(); 
} 
catch (ReflectionTypeLoadException e) 
{ 
    types = e.Types; 
} 
foreach (var t in types.Where(t => t != null)) 
{ 
    ... 
} 

それは、このかかわらずをしなければならないために絶対に迷惑なんです。あなたは、「クライアント」のコードでは、それはよりよい作るために拡張メソッドを使用することができます。

public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) 
{ 
    // TODO: Argument validation 
    try 
    { 
     return assembly.GetTypes(); 
    } 
    catch (ReflectionTypeLoadException e) 
    { 
     return e.Types.Where(t => t != null); 
    } 
} 

あなたがうまくcatchブロックの外にreturn声明を移動することを望むかもしれない - 私はそれが自分自身であることにひどく熱心ではありませんよおそらくの最短コードです...

+2

ありがとう、それは解決策のようです(私は同意します、それはクリーンな解決策ではないようです)。 – M4N

+3

このソリューションは、例外で公開されている型のリストを使用しようとすると、依然として問題が発生します。型のロード例外の理由が何であれ、FileNotFound、BadImageなどは、問題の型へのアクセスをすべてスローします。 – sweetfa

+0

@sweetfa:はい、それは非常に限られていますが、OPが名前を探すだけならば、それは大丈夫です。 –

3

Assembly.ReflectionOnlyLoadとお考えですか?あなたがしようとしていることを考えれば、十分かもしれません。

+1

はい、私はそれを考えていました。しかし、それ以外の場合、依存関係を手動でロードする必要があるため、私はそれを使用しませんでした。また、コードはReflectionOnlyLoadで実行可能ではありません(リンクしたページの「備考」を参照)。 – M4N

16

ReflectionTypeLoadExceptionを何らかの時点で受け取らなければ何もできないように見えますが、例外から提供された型を利用しようとすると、元の問題の原因となった問題が解決されませんロードに失敗します。

これを克服するには、次のコードで型をアセンブリ内にある型に限定し、述部で型のリストをさらに制限することができます。

/// <summary> 
    /// Get the types within the assembly that match the predicate. 
    /// <para>for example, to get all types within a namespace</para> 
    /// <para> typeof(SomeClassInAssemblyYouWant).Assembly.GetMatchingTypesInAssembly(item => "MyNamespace".Equals(item.Namespace))</para> 
    /// </summary> 
    /// <param name="assembly">The assembly to search</param> 
    /// <param name="predicate">The predicate query to match against</param> 
    /// <returns>The collection of types within the assembly that match the predicate</returns> 
    public static ICollection<Type> GetMatchingTypesInAssembly(this Assembly assembly, Predicate<Type> predicate) 
    { 
     ICollection<Type> types = new List<Type>(); 
     try 
     { 
      types = assembly.GetTypes().Where(i => i != null && predicate(i) && i.Assembly == assembly).ToList(); 
     } 
     catch (ReflectionTypeLoadException ex) 
     { 
      foreach (Type theType in ex.Types) 
      { 
       try 
       { 
        if (theType != null && predicate(theType) && theType.Assembly == assembly) 
         types.Add(theType); 
       } 
       // This exception list is not exhaustive, modify to suit any reasons 
       // you find for failure to parse a single assembly 
       catch (BadImageFormatException) 
       { 
        // Type not in this assembly - reference to elsewhere ignored 
       } 
      } 
     } 
     return types; 
    } 
1

私の場合、アプリケーションフォルダ内に不要なアセンブリが存在するため、同じ問題が発生していました。 Binフォルダをクリアし、アプリケーションを再構築してください。

関連する問題