web-dev-qa-db-de.com

C # Assembly.Load vs Assembly.ReflectionOnlyLoad

Ich versuche die Unterschiede zwischen Assembly.Load und Assembly.ReflectionOnlyLoad zu verstehen.

Im folgenden Code versuche ich, alle Objekte in einer gegebenen Assembly zu finden, die von einer bestimmten Schnittstelle erben:

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);
   }
}

Dieser Code funktioniert gut für mich, aber ich recherchierte nach anderen möglicherweise besseren Alternativen und stieß auf die Assembly.ReflectionOnlyLoad () -Methode.

Ich nahm an, dass, da ich keine Objekte lade oder ausführe, im Wesentlichen nur nach ihren Definitionen abfragt, dass ich ReflectionOnlyLoad für eine geringfügige Leistungssteigerung verwenden könnte.

Es stellt sich jedoch heraus, dass beim Ändern von Assembly.Load in Assembly.ReflectionOnlyLoad die folgende Fehlermeldung angezeigt wird, wenn Assembly.GetTypes () aufgerufen wird:

System.Reflection.ReflectionTypeLoadException:

Ein oder mehrere der angeforderten Typen können nicht geladen werden. Rufen Sie die LoaderExceptions-Eigenschaft ab, um weitere Informationen zu erhalten.

Ich nahm an, dass der obige Code JUST nur war, um zu reflektieren und die Bibliothek "anzuschauen" ... aber ist dies eine Art Instanz des Heisenberg-Unschärfe-Prinzips, bei dem der Blick auf die Bibliothek und die darin enthaltenen Objekte tatsächlich versucht, sie in einigen zu instanziieren Weg?

Danke, Max

44
Max Schilling

Laut Jons Antwort wäre es hilfreich zu wissen, was in LoaderExceptions ist. Anstelle dieser Informationen denke ich, dass ich eine Vermutung riskieren kann. Von MSDN :

Wenn die Assembly Abhängigkeiten hat, werden sie von der ReflectionOnlyLoad-Methode Nicht geladen. Wenn Sie Untersuchen müssen, müssen Sie sie selbst laden.

Sie müssen einen Handler an AppDomain.ReflectionOnlyAssemblyResolve anhängen, damit die CLR alle Abhängigkeiten der geladenen Assembly laden kann. Hast du das gemacht?

24
Kent Boogaart

Ich glaube, Ihr allgemeines Verständnis der Unterschiede zwischen Load und ReflectionOnlyLoad ist korrekt. Das Problem hier (denke ich) ist, dass die CLR selbst zum Laden eines Typs die Metadaten aus der Assembly lesen muss. Der Typ selbst ist in definiert. Außerdem werden die Metadaten von jeder Assembly geladen. Die Vorfahren des Typs sind in definiert. . Daher müssen Sie Assembly.ReflectionOnlyLoad für alle Assemblys aufrufen, die Typen definieren, die Vorfahren der Typen sind, die Sie laden.

Angenommen, Sie haben die folgende Klasse in Assembly A.dll definiert.

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

und die folgende in Assembly B.dll definierte Klasse.

public class MySubclass : MyBase
{
}

Wenn Sie Assembly.GetTypes in Assembly B.dll aufrufen, versucht die CLR, den Typ MySubclass und alle zugehörigen Member zu laden. Da die Methode Foo in MyBase in Assembly A.dll definiert ist (und nirgendwo in den Metadaten von B.dll vorhanden ist), gibt die CLR die Typladeausnahmen aus, wenn Assembly A.dll nicht geladen wurde.

10
C. Dragon 76

Die ReflectionOnly-Methoden sind die einzige Möglichkeit, eine bestimmte Assembly auf die Festplatte zu laden, um sie zu untersuchen, ohne die üblichen Load/LoadFrom-Regeln anzuwenden. Sie können beispielsweise eine festplattenbasierte Assembly mit derselben Identität wie eine im GAC laden. Wenn Sie dies mit LoadFrom oder LoadFile versucht haben, wird die GAC-Baugruppe IMMER geladen.

Darüber hinaus können Sie GetCustomAttributes (...) für die zurückgegebene Assembly-Instanz nicht aufrufen, da dies versucht, die Attribute in der Assembly zu instanziieren, die ReflectionOnly sind. Dazu müssen Sie die statischen Methoden der CustomAttributeData-Klasse verwenden.

In einer Assembly, die über ReflectionOnly geladen wurde, dürfen keine Typen instanziiert werden.

8
x0n

Von Assembly kann keine Methode ausgeführt werden, die mit ReflectionOnlyLoad() geladen wird. Sie erhalten InvalidOperationException. Dies ist also eine sichere Methode, um den Assembly-Inhalt mithilfe von Reflektion zu ermitteln.

3
abatishchev

Ein weiterer großer Unterschied zwischen den beiden ist Assembly.Load fügt die Assembly in die AppDomain ein, wobei Assembly.ReflectionOnlyLoad die Assembly nicht in die AppDomain einfügt.

code, der im Detail angezeigt wird.

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