You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C# System.Reflection.Emit中为类类型属性设置默认值

使用System.Reflection.Emit为动态类属性设置默认值

我正在用C#的System.Reflection.Emit在运行时创建动态类,想实现类似以下编译时类的效果:

public class RequestForTest
{
    public string variableName { get; set; }
    public MyClass myClass { get; set; } = new MyClass();
}

也就是要给动态类的myClass属性设置默认值(实例化对应的类),该怎么实现?

更新内容

我定义了ClassProperty类:

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

我的动态类创建代码如下:

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

问题修复与实现说明

你的代码存在两处关键错误,导致ClassProperty属性的默认值无法正确设置:

  1. 字段引用错误:在set_ClassProperty和get_ClassProperty方法中,错误地引用了fieldBuilder(对应_name字段),而非fieldBuilder1(对应_classProperty字段)。
  2. 构造函数定义冲突:同时调用DefineConstructor和DefineDefaultConstructor会导致构造函数重复定义,只需保留一种方式即可。

以下是修正后的完整代码:

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

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

class Program
{
    static void Main()
    {
        string className = "ReflectionDemo";
        AssemblyName assemblyName = new AssemblyName(className);

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

        // 定义Name属性对应的私有字段
        FieldBuilder nameField = typeBuilder.DefineField(
            "_name",
            typeof(string),
            FieldAttributes.Private);

        // 构建Name属性
        PropertyBuilder nameProperty = typeBuilder.DefineProperty(
            "Name",
            PropertyAttributes.None,
            typeof(string),
            Type.EmptyTypes);

        // 构建Name的Setter
        MethodBuilder nameSetter = typeBuilder.DefineMethod(
            "set_Name",
            MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,
            typeof(void),
            new[] { typeof(string) });

        ILGenerator nameSetterIL = nameSetter.GetILGenerator();
        nameSetterIL.Emit(OpCodes.Ldarg_0);
        nameSetterIL.Emit(OpCodes.Ldarg_1);
        nameSetterIL.Emit(OpCodes.Stfld, nameField);
        nameSetterIL.Emit(OpCodes.Ret);
        nameProperty.SetSetMethod(nameSetter);

        // 构建Name的Getter
        MethodBuilder nameGetter = typeBuilder.DefineMethod(
            "get_Name",
            MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,
            typeof(string),
            Type.EmptyTypes);

        ILGenerator nameGetterIL = nameGetter.GetILGenerator();
        nameGetterIL.Emit(OpCodes.Ldarg_0);
        nameGetterIL.Emit(OpCodes.Ldfld, nameField);
        nameGetterIL.Emit(OpCodes.Ret);
        nameProperty.SetGetMethod(nameGetter);

        // 定义ClassProperty属性对应的私有字段
        FieldBuilder classPropertyField = typeBuilder.DefineField(
            "_classProperty",
            typeof(ClassProperty),
            FieldAttributes.Private);

        // 构建ClassProperty属性
        PropertyBuilder classProperty = typeBuilder.DefineProperty(
            "ClassProperty",
            PropertyAttributes.None,
            typeof(ClassProperty),
            Type.EmptyTypes);

        // 构建ClassProperty的Setter
        MethodBuilder classPropertySetter = typeBuilder.DefineMethod(
            "set_ClassProperty",
            MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,
            typeof(void),
            new[] { typeof(ClassProperty) });

        ILGenerator cpsIL = classPropertySetter.GetILGenerator();
        cpsIL.Emit(OpCodes.Ldarg_0);
        cpsIL.Emit(OpCodes.Ldarg_1);
        cpsIL.Emit(OpCodes.Stfld, classPropertyField); // 修正为正确的字段
        cpsIL.Emit(OpCodes.Ret);
        classProperty.SetSetMethod(classPropertySetter);

        // 构建ClassProperty的Getter
        MethodBuilder classPropertyGetter = typeBuilder.DefineMethod(
            "get_ClassProperty",
            MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,
            typeof(ClassProperty),
            Type.EmptyTypes);

        ILGenerator cpgIL = classPropertyGetter.GetILGenerator();
        cpgIL.Emit(OpCodes.Ldarg_0);
        cpgIL.Emit(OpCodes.Ldfld, classPropertyField); // 修正为正确的字段
        cpgIL.Emit(OpCodes.Ret);
        classProperty.SetGetMethod(classPropertyGetter);

        // 自定义无参构造函数,实现字段初始化
        ConstructorBuilder ctor = typeBuilder.DefineConstructor(
            MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
            CallingConventions.Standard,
            Type.EmptyTypes);

        ILGenerator ctorIL = ctor.GetILGenerator();
        // 先调用基类(object)的构造函数
        ConstructorInfo objectCtor = typeof(object).GetConstructor(Type.EmptyTypes)!;
        ctorIL.Emit(OpCodes.Ldarg_0);
        ctorIL.Emit(OpCodes.Call, objectCtor);

        // 初始化_name字段
        ctorIL.Emit(OpCodes.Ldarg_0);
        ctorIL.Emit(OpCodes.Ldstr, "Anh");
        ctorIL.Emit(OpCodes.Stfld, nameField);

        // 初始化_classProperty字段,实例化ClassProperty
        ConstructorInfo classPropertyCtor = typeof(ClassProperty).GetConstructor(Type.EmptyTypes)!;
        ctorIL.Emit(OpCodes.Ldarg_0);
        ctorIL.Emit(OpCodes.Newobj, classPropertyCtor);
        ctorIL.Emit(OpCodes.Stfld, classPropertyField);

        ctorIL.Emit(OpCodes.Ret);

        // 创建动态类型
        Type dynamicType = typeBuilder.CreateType()!;
        // 实例化动态类
        dynamic instance = Activator.CreateInstance(dynamicType)!;

        // 验证结果
        Console.WriteLine($"Name: {instance.Name}");
        Console.WriteLine($"ClassProperty.Age: {instance.ClassProperty.Age}"); // 输出5,说明ClassProperty已正确初始化
        Console.ReadKey();
    }
}

关键实现要点

  • 字段与属性的对应关系:确保每个属性的Getter/Setter都正确引用对应的私有字段,这是最容易出错的环节。
  • 构造函数初始化逻辑:在自定义无参构造函数中,先调用基类构造函数,再通过Newobj指令实例化ClassProperty,最后将实例赋值给对应私有字段,以此实现编译时= new MyClass()的默认值效果。
  • 避免构造函数重复定义:不要同时调用DefineConstructor和DefineDefaultConstructor,如需自定义初始化逻辑,使用DefineConstructor实现即可。

内容的提问来源于stack exchange,提问作者Đặng Đức

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 00:10:47