如何通过Reflection.Emit在运行时为已有类添加属性?
问题分析与解决方案
核心问题
无法通过Reflection.Emit直接修改已加载的现有类——CLR不允许类被加载到AppDomain后修改其结构(包括添加字段、属性)。你当前的代码只是在动态程序集中创建了一个同名的新类,和原程序集里的MyClass毫无关联,所以原实例的属性不会有任何变化。
你的代码问题点
这段代码里的tb = mb.DefineType("MyClass")生成的是动态程序集内的全新类型,和你原本的MyClass属于不同程序集、不同Type对象,因此:
- 后续创建的
new MyClass()还是原类型的实例,不会包含动态添加的testProp - 动态生成的类只有调用
tb.CreateType()后才会存在,且需通过该Type创建实例才能使用
可行替代方案
方案1:动态生成子类扩展原类
既然不能修改原类,可以通过继承原类,动态生成子类来添加新属性/字段:
var originalType = typeof(MyClass); var assemblyName = new AssemblyName("DynamicExtensions"); AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); ModuleBuilder mb = ab.DefineDynamicModule(assemblyName.Name); // 生成继承自MyClass的子类 TypeBuilder tb = mb.DefineType( "MyClassExtended", TypeAttributes.Public | TypeAttributes.Class, originalType); // 给子类添加属性 AddProperty(tb, "testProp", typeof(string)); // 创建动态类型并实例化 Type extendedType = tb.CreateType(); var extendedInstance = Activator.CreateInstance(extendedType) as MyClass; // 验证属性存在 Console.WriteLine(extendedType.GetProperties().Length); foreach (var prop in extendedType.GetProperties()) { Console.WriteLine(prop.Name); }
方案2:使用ExpandoObject(弱类型场景)
如果不需要强类型,可以用ExpandoObject包装原类实例,动态添加属性:
dynamic expando = new ExpandoObject(); var originalInstance = new MyClass(); // 拷贝原类属性到Expando foreach (var prop in originalInstance.GetType().GetProperties()) { ((IDictionary<string, object>)expando)[prop.Name] = prop.GetValue(originalInstance); } // 添加新属性 expando.testProp = "new value"; // 使用动态属性 Console.WriteLine(expando.testProp);
方案3:装饰器模式(强类型扩展)
定义一个装饰类包装原实例,添加额外属性:
public class MyClassDecorator { private readonly MyClass _original; public string testProp { get; set; } public MyClassDecorator(MyClass original) { _original = original; } // 暴露原类的属性/方法 public string OriginalProp => _original.OriginalProp; } // 使用示例 var original = new MyClass(); var decorated = new MyClassDecorator(original); decorated.testProp = "test"; Console.WriteLine(decorated.testProp);
内容的提问来源于stack exchange,提问作者Ivan Kolesnyk
相关产品推荐
相关产品推荐

