web-dev-qa-db-fra.com

C # Assembly.Load vs Assembly.ReflectionOnlyLoad

J'essaie de comprendre les différences entre Assembly.Load et Assembly.ReflectionOnlyLoad.

Dans le code ci-dessous, j'essaie de trouver tous les objets d'un assemblage donné qui héritent d'une interface donnée:

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

Ce code fonctionne bien pour moi, mais je faisais des recherches sur d’autres alternatives éventuellement meilleures et j’ai découvert la méthode Assembly.ReflectionOnlyLoad ().

Comme je ne charge ni n'exécute aucun des objets, j'ai supposé que je pouvais utiliser ReflectionOnlyLoad pour une légère augmentation des performances ...

Mais il se trouve que lorsque je modifie Assembly.Load en Assembly.ReflectionOnlyLoad, l'erreur suivante apparaît lors de l'appel de Assembly.GetTypes ():

System.Reflection.ReflectionTypeLoadException:

Impossible de charger un ou plusieurs des fichiers types demandés. Récupérer le LoaderExceptions pour plus information.

J'ai supposé que le code ci-dessus était juste en train de faire de la réflexion et de "regarder" la bibliothèque ... façon?

Merci, Max

44
Max Schilling

Selon la réponse de Jon, il serait utile de savoir ce que contient LoaderExceptions. Au lieu de cette information, je pense pouvoir deviner. De MSDN :

Si l'Assemblée a des dépendances, le La méthode ReflectionOnlyLoad ne fonctionne pas chargez-les. Si vous devez examiner eux, vous devez les charger vous-même.

Vous devez associer un gestionnaire à AppDomain.ReflectionOnlyAssemblyResolve pour aider le CLR à charger les dépendances de l'assembly que vous chargez. Avez-vous fait cela?

24
Kent Boogaart

Je pense que votre compréhension générale des différences entre Load et ReflectionOnlyLoad est correcte. Le problème ici (je pense) est que même pour simplement charger un type, le CLR doit lire les métadonnées de l'assembly, le type lui-même est défini dans ainsi que pour charger les métadonnées de chaque assemblage dans lequel les ancêtres du type sont définis . Vous devez donc appeler Assembly.ReflectionOnlyLoad sur tous les assemblys qui définissent des types ancêtres des types que vous chargez.

Pour donner un exemple, supposons que la classe suivante soit définie dans Assembly A.dll.

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

et la classe suivante définie dans Assembly B.dll.

public class MySubclass : MyBase
{
}

Lorsque vous appelez Assembly.GetTypes sur Assembly B.dll, le CLR essaiera de charger le type MySubclass et tous ses membres. Parce que la méthode Foo est définie dans MyBase dans Assembly A.dll (et n'existe nulle part dans les métadonnées de B.dll), le CLR lève les exceptions de chargement de type si Assembly A.dll n'a pas été chargé.

10
C. Dragon 76

Les méthodes ReflectionOnly sont le seul moyen de charger un assemblage spécifique sur le disque à examiner sans passer par les règles habituelles Load/LoadFrom. Par exemple, vous pouvez charger un assembly basé sur disque avec la même identité que celle du GAC. Si vous avez essayé avec LoadFrom ou LoadFile, l’ensemble GAC est TOUJOURS chargé.

En outre, vous ne pouvez pas appeler GetCustomAttributes (...) sur l'instance d'assembly de retour, car cela tentera d'instancier les attributs sur l'assembly, qui sont ReflectionOnly. Vous devez pour cela utiliser les méthodes statiques de la classe CustomAttributeData.

Aucun type d'un assemblage chargé via ReflectionOnly ne peut être instancié.

8
x0n

Aucune méthode ne peut être exécutée depuis Assembly, chargée avec ReflectionOnlyLoad(), vous obtiendrez InvalidOperationException. C'est donc un moyen sûr de déterminer le contenu de l'Assemblée à l'aide de la réflexion.

3
abatishchev

Une autre grande différence entre les deux est que Assembly.Load ajoute l'assembly dans le AppDomain, où en tant que Assembly.ReflectionOnlyLoad ne l'ajoutera pas au AppDomain

code à afficher en détail.

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
Gerrie Pretorius