web-dev-qa-db-ja.com

C#Assembly.LoadとAssembly.ReflectionOnlyLoad

Assembly.LoadとAssembly.ReflectionOnlyLoadの違いを理解しようとしています。

以下のコードでは、特定のインターフェイスから継承する特定のアセンブリ内のすべてのオブジェクトを検索しようとしています。

var myTypes = new List<Type>();

var Assembly = Assembly.Load("MyProject.Components");

foreach (var type in Assembly.GetTypes())
{
   if (type.GetInterfaces().Contains(typeof(ISuperInterface)))
   {
      myTypes.Add(type);
   }
}

このコードは私には問題なく機能しますが、他の可能性のある代替案を調査していて、Assembly.ReflectionOnlyLoad()メソッドを見つけました。

私はオブジェクトをロードまたは実行していないので、本質的には、ReflectionOnlyLoadを使用してわずかにパフォーマンスを向上させることができるそれらの定義を照会するだけだと思いました...

しかし、Assembly.LoadをAssembly.ReflectionOnlyLoadに変更すると、Assembly.GetTypes()を呼び出すときに次のエラーが発生します。

System.Reflection.ReflectionTypeLoadException:

要求されたタイプの1つ以上をロードできません。詳細については、LoaderExceptionsプロパティを取得してください。

上記のコードはリフレクションを実行してライブラリを「見る」だけだと思いましたが、これはハイゼンベルク不確定性原理の一種のインスタンスであり、ライブラリとその中のオブジェクトを見ると、実際にそれらをインスタンス化しようとします仕方?

ありがとう、マックス

46
Max Schilling

Jonの返答に従って、LoaderExceptionsの内容を知っておくと役に立ちます。この情報の代わりに、私は推測を危険にさらすことができると思います。から [〜#〜] msdn [〜#〜]

アセンブリに依存関係がある場合、ReflectionOnlyLoadメソッドはそれらをロードしません。それらを調べる必要がある場合は、自分でロードする必要があります。

ロードするアセンブリの依存関係をCLRがロードできるようにするには、ハンドラーをAppDomain.ReflectionOnlyAssemblyResolveにアタッチする必要があります。これをやりましたか?

26
Kent Boogaart

LoadとReflectionOnlyLoadの違いについての一般的な理解は正しいと思います。ここでの問題(私は思う)は、タイプを単にロードする場合でも、CLRはタイプ自体が定義されているアセンブリからメタデータを読み取る必要があるということですまた、タイプの祖先が定義されているすべてのアセンブリからメタデータをロードします)。したがって、ロードする型の祖先である型を定義するすべてのアセンブリでAssembly.ReflectionOnlyLoadを呼び出す必要があります。

例として、次のクラスがアセンブリA.dllで定義されているとします。

public class MyBase
{
   public void Foo() { }
}

アセンブリB.dllで定義されている次のクラス。

public class MySubclass : MyBase
{
}

アセンブリB.dllでAssembly.GetTypesを呼び出すと、CLRはMySubclassタイプとそのすべてのメンバーをロードしようとします。メソッドFooはアセンブリA.dllのMyBaseで定義されている(そしてB.dllのメタデータのどこにも存在しない)ため、アセンブリA.dllが読み込まれていない場合、CLRは型読み込み例外をスローします。

10
C. Dragon 76

ReflectionOnlyメソッドは、通常のLoad/LoadFromルールを経由せずに特定のアセンブリをディスクにロードして検査できる唯一の方法です。たとえば、GAC内のものと同じIDを持つディスクベースのアセンブリをロードできます。 LoadFromまたはLoadFileでこれを試した場合、GACアセンブリは常に読み込まれます。

さらに、これは、アセンブリの属性であるReflectionOnlyをインスタンス化しようとするため、戻りアセンブリインスタンスでGetCustomAttributes(...)を呼び出さない場合があります。これには、CustomAttributeDataクラスの静的メソッドを使用する必要があります。

ReflectionOnlyを介して読み込まれたアセンブリのタイプはインスタンス化できません。

8
x0n

ReflectionOnlyLoad()でロードされたアセンブリからメソッドを実行することはできません。InvalidOperationExceptionを取得します。したがって、これはリフレクションを使用してアセンブリコンテンツを決定する安全な方法です。

3
abatishchev

2つのもう1つの大きな違いは、Assembly.LoadがアセンブリをAppDomainに追加することです。ここで、Assembly.ReflectionOnlyLoadはアセンブリをAppDomainに追加しません。

詳細に表示するコード。

public void AssemblyLoadTest(string assemblyToLoad)
{
    var initialAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    Assembly.ReflectionOnlyLoad(assemblyToLoad);
    var reflectionOnlyAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //4

    //Shows that Assembly is NOT loaded in to AppDomain with Assembly.ReflectionOnlyLoad
    Assert.AreEqual(initialAppDomainAssemblyCount, reflectionOnlyAppDomainAssemblyCount); // 4 == 4

    Assembly.Load(assemblyToLoad);
    var loadAppDomainAssemblyCount = AppDomain.CurrentDomain.GetAssemblies().Count(); //5

    //Shows that Assembly is loaded in to AppDomain with Assembly.Load
    Assert.AreNotEqual(initialAppDomainAssemblyCount, loadAppDomainAssemblyCount); // 4 != 5
}
0