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

使用反射为动态创建的属性赋值时遇到的问题

问题分析与解决方案

你的代码核心问题在于:为同一个属性的get和set方法分别定义了两个独立的后备字段,导致赋值操作(set)和取值操作(get)完全在不同的存储位置进行,自然看不到赋值后的结果。此外,你提到“不需要后备字段”是误解——普通的可读写属性必须依赖某个存储载体来保存值,C#的自动属性也是编译器自动生成了后备字段,动态创建属性时需要显式定义这个共享的存储字段。

修正后的代码

替换原代码中的foreach循环部分:

foreach (var category in model.Categories)
{
    var propertyName = category.ColumnName.Replace(" ", "_");
    var newPropType = typeof(string);

    // 1. 定义该属性唯一的私有后备字段
    FieldBuilder backingField = typeBuilder.DefineField($"_{propertyName}", newPropType, FieldAttributes.Private);

    // 2. 定义属性本身
    PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, newPropType, null);

    // 3. 实现get方法:从共享字段读取值
    MethodBuilder getMethod = typeBuilder.DefineMethod($"get_{propertyName}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, newPropType, Type.EmptyTypes);
    ILGenerator getIL = getMethod.GetILGenerator();
    getIL.Emit(OpCodes.Ldarg_0);
    getIL.Emit(OpCodes.Ldfld, backingField);
    getIL.Emit(OpCodes.Ret);

    // 4. 实现set方法:将值写入共享字段
    MethodBuilder setMethod = typeBuilder.DefineMethod($"set_{propertyName}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new Type[] { newPropType });
    ILGenerator setIL = setMethod.GetILGenerator();
    setIL.Emit(OpCodes.Ldarg_0);
    setIL.Emit(OpCodes.Ldarg_1);
    setIL.Emit(OpCodes.Stfld, backingField);
    setIL.Emit(OpCodes.Ret);

    // 5. 将get/set方法关联到属性
    propertyBuilder.SetGetMethod(getMethod);
    propertyBuilder.SetSetMethod(setMethod);
}

关键修正点

  • 每个属性只创建一个私有后备字段,让get和set方法都操作这个字段,保证赋值和取值的存储位置一致。
  • 先创建后备字段,再在get/set的IL指令中引用该字段,避免重复创建字段(原代码中每次调用DefineField都会生成新字段,即使名称重复也会因为调用时机问题导致异常)。

内容的提问来源于stack exchange,提问作者CrsB1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:55:15