How to set default property value of class type in C# System.Reflection.Emit

184 views Asked by At

I am using System.Reflection in C# to create a dynamic object class at runtime.

This is the example object class that I want to create at runtime.

public class RequestForTest
{
    public string variableName { get; set; }
    public MyClass myClass { get; set; }
}

For this class, can I set the default value of property name "myClass" like:

public MyClass myClass { get; set; } = new MyClass();

at runtime? And how can I resolve it?

Thank you for your support!

UPDATE

ClassProperty.cs

    public class ClassProperty
    {
        public string? Name { get; set; }
        public int Age { get; set; } = 5;
    }

My create object class code.

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

        string className = "ReflectionDemo";
        AssemblyName assemblyName = new AssemblyName(className);

        AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(className + "." + className + ".dll");
        TypeBuilder typeBuilder = moduleBuilder.DefineType(className,
                TypeAttributes.Public |
                TypeAttributes.Class |
                TypeAttributes.AutoClass |
                TypeAttributes.AnsiClass |
                TypeAttributes.BeforeFieldInit |
                TypeAttributes.AutoLayout,
                null);

        // Add a private field of type int (Int32).
        FieldBuilder fieldBuilder = typeBuilder.DefineField(
            "_name",
            typeof(string),
            FieldAttributes.Private);

        // Next, we build the property. This involves building the property itself, as well as the
        // getter and setter methods.
        PropertyBuilder pbNumber = typeBuilder.DefineProperty(
            "Name", // Name
            PropertyAttributes.None,
            typeof(string), // Type of the property
            new Type[0]); // Types of indices, if any

        MethodBuilder mbSetNumber = typeBuilder.DefineMethod(
            "set_Name", // Name - setters are set_Property by convention
                                 // Setter is a special method and we don't want it to appear to callers from C#
            MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,
            typeof(void), // Setters don't return a value
            new[] { typeof(string) }); // We have a single argument of type System.Int32

        // To generate the body of the method, we'll need an IL generator
        ILGenerator il = mbSetNumber.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0); // Load this
        il.Emit(OpCodes.Ldarg_1); // Load the new value
        il.Emit(OpCodes.Stfld, fieldBuilder); // Save the new value to this.m_number
        il.Emit(OpCodes.Ret); // Return

        // Finally, link the method to the setter of our property
        pbNumber.SetSetMethod(mbSetNumber);

        MethodBuilder mbGetNumber = typeBuilder.DefineMethod(
            "get_Name",
            MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,
            typeof(string),
            new Type[0]);

        il = mbGetNumber.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0); // Load this
        il.Emit(OpCodes.Ldfld, fieldBuilder); // Load the value of this.m_number
        il.Emit(OpCodes.Ret); // Return the value

        pbNumber.SetGetMethod(mbGetNumber);

        //////////////////////////////////////////////////////////////////
        // Create SystemReflection.ClassProperty
        FieldBuilder fieldBuilder1 = typeBuilder.DefineField(
            "_classProperty",
            typeof(ClassProperty),
            FieldAttributes.Private);

        // Next, we build the property. This involves building the property itself, as well as the
        // getter and setter methods.
        PropertyBuilder pbNumber1 = typeBuilder.DefineProperty(
            "ClassProperty", // Name
            PropertyAttributes.None,
            typeof(ClassProperty), // Type of the property
            new Type[0]); // Types of indices, if any

        MethodBuilder mbSetNumber1 = typeBuilder.DefineMethod(
            "set_ClassProperty", // Name - setters are set_Property by convention
                               // Setter is a special method and we don't want it to appear to callers from C#
            MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,
            typeof(void), // Setters don't return a value
            new[] { typeof(ClassProperty) }); // We have a single argument of type System.Int32

        // To generate the body of the method, we'll need an IL generator
        ILGenerator il1 = mbSetNumber1.GetILGenerator();
        il1.Emit(OpCodes.Ldarg_0); // Load this
        il1.Emit(OpCodes.Ldarg_1); // Load the new value
        il1.Emit(OpCodes.Stfld, fieldBuilder); // Save the new value to this.m_number
        il1.Emit(OpCodes.Ret); // Return

        // Finally, link the method to the setter of our property
        pbNumber1.SetSetMethod(mbSetNumber1);

        MethodBuilder mbGetNumber1 = typeBuilder.DefineMethod(
            "get_ClassProperty",
            MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,
            typeof(ClassProperty),
            new Type[0]);

        il1 = mbGetNumber1.GetILGenerator();
        il1.Emit(OpCodes.Ldarg_0); // Load this
        il1.Emit(OpCodes.Ldfld, fieldBuilder); // Load the value of this.m_number
        il1.Emit(OpCodes.Ret); // Return the value

        pbNumber1.SetGetMethod(mbGetNumber1);

        ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public |
                                           MethodAttributes.SpecialName |
                                           MethodAttributes.RTSpecialName, CallingConventions.Standard, Type.EmptyTypes);

        //ConstructorInfo? constructorInfo = typeof(object).GetConstructor(Type.EmptyTypes);
        ConstructorInfo constructorInfo = typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
        ILGenerator constructorILGenerator = constructorBuilder.GetILGenerator();
        if (constructorInfo == null)
            throw new Exception("Create constructor failed");

        constructorILGenerator.Emit(OpCodes.Ldarg_0);
        constructorILGenerator.Emit(OpCodes.Call, constructorInfo);
        // Set Name
        constructorILGenerator.Emit(OpCodes.Ldarg_0);
        constructorILGenerator.Emit(OpCodes.Ldstr, "Anh");
        constructorILGenerator.Emit(OpCodes.Stfld, fieldBuilder);
        // Set ClassProperty
        constructorILGenerator.Emit(OpCodes.Ldarg_0);

        ConstructorInfo? conInfo = typeof(ClassProperty).GetConstructor(new Type[0]);
        if (conInfo == null)
            throw new Exception($"Constructor on type {typeof(ClassProperty).Name} not found.");

        constructorILGenerator.Emit(OpCodes.Newobj, typeof(ClassProperty));
        constructorILGenerator.Emit(OpCodes.Stfld, fieldBuilder1);
        constructorILGenerator.Emit(OpCodes.Nop);
        constructorILGenerator.Emit(OpCodes.Ret);

        var type = typeBuilder.CreateType();
        if (type == null)
            throw new Exception($"Create type of {className} failed!");


        var instanceType = Activator.CreateInstance(type);
        //instanceType.GetType().GetProperty("ClassProperty").SetValue(instanceType, Activator.CreateInstance(typeof(ClassProperty)));
        //Console.WriteLine("A");
        Console.ReadKey();
0

There are 0 answers