Maison >développement back-end >C++ >Comment générer dynamiquement une classe C # à l'exécution à l'aide de System.Reflection.Emit?

Comment générer dynamiquement une classe C # à l'exécution à l'aide de System.Reflection.Emit?

Mary-Kate Olsen
Mary-Kate Olsenoriginal
2025-01-30 15:06:11295parcourir

How to dynamically generate a C# class at runtime using System.Reflection.Emit?

Comment générer dynamiquement une classe à l'exécution?

Considérez le scénario suivant: Vous avez une classe qui représente un ensemble de champs et leurs types:

public class Field
{
    public string FieldName;
    public string FieldType;
} 

De plus, vous possédez une liste d'objets de champ avec des valeurs prédéfinies:

{ "EmployeeID", "int" },
{ "EmployeeName", "string" },
{ "Designation", "string" }

Votre objectif est de créer une classe dynamique nommée DynamicClass qui aura des propriétés correspondant à chaque champ de la liste:

class DynamicClass
{
    int EmployeeID,
    string EmployeeName,
    string Designation
}

Solution utilisant System.Reflection.Emit

Pour accomplir cette création de classe dynamique, vous pouvez tirer parti des capacités de l'espace de noms System.Reflection.Emit. Bien qu'il nécessite une certaine compétence avec l'espace de noms, il offre un mécanisme robuste pour générer des cours à l'exécution.

Détails d'implémentation

Initialement, vous devez créer un objet de type Builder, qui servira de fondation pour votre classe dynamique. Cela implique de définir une signature, un assemblage et un module de type. Anschließend, pour chaque champ de votre liste, vous devez générer une propriété dans la classe dynamique.

Pour créer une propriété, vous établissez d'abord un champ privé qui conservera la valeur de la propriété. Par la suite, vous définissez les attributs de la propriété et créez des méthodes pour obtenir et définir sa valeur. Ces méthodes utiliseront le champ privé pour manipuler l'état de la propriété.

Exemple de code

using System;
using System.Reflection;
using System.Reflection.Emit;

namespace TypeBuilderNamespace
{
    public static class MyTypeBuilder
    {
        public static void CreateNewObject()
        {
            var myType = CompileResultType();
            var myObject = Activator.CreateInstance(myType);
        }
        public static Type CompileResultType()
        {
            TypeBuilder tb = GetTypeBuilder();
            ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

            // Assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
            foreach (var field in yourListOfFields)
                CreateProperty(tb, field.FieldName, field.FieldType);

            Type objectType = tb.CreateType();
            return objectType;
        }

        private static TypeBuilder GetTypeBuilder()
        {
            var typeSignature = "MyDynamicType";
            var an = new AssemblyName(typeSignature);
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
            TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
                    TypeAttributes.Public |
                    TypeAttributes.Class |
                    TypeAttributes.AutoClass |
                    TypeAttributes.AnsiClass |
                    TypeAttributes.BeforeFieldInit |
                    TypeAttributes.AutoLayout,
                    null);
            return tb;
        }

        private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
        {
            FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);

            PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
            MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
            ILGenerator getIl = getPropMthdBldr.GetILGenerator();

            getIl.Emit(OpCodes.Ldarg_0);
            getIl.Emit(OpCodes.Ldfld, fieldBuilder);
            getIl.Emit(OpCodes.Ret);

            MethodBuilder setPropMthdBldr =
                tb.DefineMethod("set_" + propertyName,
                  MethodAttributes.Public |
                  MethodAttributes.SpecialName |
                  MethodAttributes.HideBySig,
                  null, new[] { propertyType });

            ILGenerator setIl = setPropMthdBldr.GetILGenerator();
            Label modifyProperty = setIl.DefineLabel();
            Label exitSet = setIl.DefineLabel();

            setIl.MarkLabel(modifyProperty);
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Stfld, fieldBuilder);

            setIl.Emit(OpCodes.Nop);
            setIl.MarkLabel(exitSet);
            setIl.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(getPropMthdBldr);
            propertyBuilder.SetSetMethod(setPropMthdBldr);
        }
    }
}

En utilisant cette approche, vous pouvez produire dynamiquement des classes conformes à vos définitions de champ spécifiées, vous permettant Pour créer des représentations d'objets flexibles et adaptables à l'exécution.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn