Partager via


Classe System.Reflection.Emit.AssemblyBuilder

Cet article vous offre des remarques complémentaires à la documentation de référence pour cette API.

Un assembly dynamique est un assembly créé à l’aide des API d’émission de Réflexions ion. Un assembly dynamique peut référencer des types définis dans un autre assembly dynamique ou statique. Vous pouvez utiliser AssemblyBuilder pour générer des assemblys dynamiques en mémoire et exécuter leur code pendant la même exécution de l’application. Dans .NET 9, nous avons ajouté un nouveau PersistedAssemblyBuilder avec une implémentation entièrement gérée de l’émission de réflexion qui vous permet d’enregistrer l’assembly dans un fichier. Dans .NET Framework, vous pouvez effectuer les deux opérations : exécuter l’assembly dynamique et l’enregistrer dans un fichier. L’assembly dynamique créé pour l’enregistrement est appelé assembly persistant , tandis que l’assembly en mémoire seule standard est appelé temporaire ou exécutable. Dans .NET Framework, un assembly dynamique peut se composer d’un ou plusieurs modules dynamiques. Dans .NET Core et .NET 5+, un assembly dynamique ne peut se composer qu’d’un seul module dynamique.

La façon dont vous créez une instance diffère pour chaque implémentation, mais d’autres étapes pour définir un module, un type, une AssemblyBuilder méthode ou une énumération, et pour l’écriture d’il, sont assez similaires.

Assemblys dynamiques exécutables dans .NET

Pour obtenir un objet exécutable AssemblyBuilder , utilisez la AssemblyBuilder.DefineDynamicAssembly méthode. Les assemblys dynamiques peuvent être créés à l’aide de l’un des modes d’accès suivants :

Le mode d’accès doit être spécifié en fournissant la valeur appropriée AssemblyBuilderAccess dans l’appel à la AssemblyBuilder.DefineDynamicAssembly méthode lorsque l’assembly dynamique est défini et ne peut pas être modifié ultérieurement. Le runtime utilise le mode d’accès d’un assembly dynamique pour optimiser la représentation interne de l’assembly.

L’exemple suivant montre comment créer et exécuter un assembly :

public void CreateAndRunAssembly(string assemblyPath)
{
    AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("MyAssembly"), AssemblyBuilderAccess.Run);
    ModuleBuilder mob = ab.DefineDynamicModule("MyModule");
    TypeBuilder tb = mob.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
    MethodBuilder mb = tb.DefineMethod("SumMethod", MethodAttributes.Public | MethodAttributes.Static,
                                                                   typeof(int), new Type[] {typeof(int), typeof(int)});
    ILGenerator il = mb.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Ret);

    Type type = tb.CreateType();

    MethodInfo method = type.GetMethod("SumMethod");
    Console.WriteLine(method.Invoke(null, new object[] { 5, 10 }));
}

Assemblys dynamiques persistants dans .NET

Le nouveau PersistedAssemblyBuilder type dérivé du AssemblyBuilder fichier et permet d’enregistrer les assemblys dynamiques dans .NET Core, case activée les scénarios d’utilisation et les exemples de la page PersistedAssemblyBuilder.

Assemblys dynamiques persistants dans .NET Framework

Dans .NET Framework, les assemblys dynamiques et les modules peuvent être enregistrés dans des fichiers. Pour prendre en charge cette fonctionnalité, l’énumération AssemblyBuilderAccess déclare deux champs supplémentaires : Save et RunAndSave.

Les modules dynamiques de l’assembly dynamique persistant sont enregistrés lorsque l’assembly dynamique est enregistré à l’aide de la Save méthode. Pour générer un exécutable, la SetEntryPoint méthode doit être appelée pour identifier la méthode qui est le point d’entrée de l’assembly. Les assemblys sont enregistrés sous forme de DLL par défaut, sauf si la SetEntryPoint méthode demande la génération d’une application console ou d’une application Windows.

L’exemple suivant montre comment créer, enregistrer et exécuter un assembly à l’aide de .NET Framework.

public void CreateRunAndSaveAssembly(string assemblyPath)
{
    AssemblyBuilder ab = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("MyAssembly"), AssemblyBuilderAccess.RunAndSave);
    ModuleBuilder mob = ab.DefineDynamicModule("MyAssembly.dll");
    TypeBuilder tb = mob.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);
    MethodBuilder meb = tb.DefineMethod("SumMethod", MethodAttributes.Public | MethodAttributes.Static,
                                                                   typeof(int), new Type[] {typeof(int), typeof(int)});
    ILGenerator il = meb.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Ret);

    Type type = tb.CreateType();

    MethodInfo method = type.GetMethod("SumMethod");
    Console.WriteLine(method.Invoke(null, new object[] { 5, 10 }));
    ab.Save("MyAssembly.dll");
}

Certaines méthodes de la classe de base Assembly , telles que GetModules et GetLoadedModules, ne fonctionnent pas correctement quand elles sont appelées à partir d’objets AssemblyBuilder . Vous pouvez charger l’assembly dynamique défini et appeler les méthodes sur l’assembly chargé. Par exemple, pour vous assurer que les modules de ressources sont inclus dans la liste des modules retournés, appelez GetModules l’objet chargé Assembly . Si un assembly dynamique contient plusieurs modules dynamiques, le nom du fichier manifeste de l’assembly doit correspondre au nom du module spécifié comme premier argument de la DefineDynamicModule méthode.

La signature d’un assembly dynamique à l’aide KeyPair de n’est pas effective tant que l’assembly n’est pas enregistré sur le disque. Par conséquent, les noms forts ne fonctionnent pas avec les assemblys dynamiques temporaires.

Les assemblys dynamiques peuvent référencer des types définis dans un autre assembly. Un assembly dynamique temporaire peut référencer en toute sécurité des types définis dans un autre assembly dynamique temporaire, un assembly dynamique persistant ou un assembly statique. Toutefois, le Common Language Runtime n’autorise pas un module dynamique persistant à référencer un type défini dans un module dynamique temporaire. Cela est dû au fait que lorsque le module dynamique persistant est chargé après avoir été enregistré sur le disque, le runtime ne peut pas résoudre les références aux types définis dans le module dynamique temporaire.

Restrictions sur l’émission vers des domaines d’application distants

Certains scénarios nécessitent la création et l’exécution d’un assembly dynamique dans un domaine d’application distant. Réflexions’émission d’émission n’autorise pas l’émission d’un assembly dynamique directement vers un domaine d’application distant. La solution consiste à émettre l’assembly dynamique dans le domaine d’application actuel, à enregistrer l’assembly dynamique émis sur le disque, puis à charger l’assembly dynamique dans le domaine d’application distant. Les domaines de communication à distance et d’application sont pris en charge uniquement dans .NET Framework.