使用Reflection.Emit为现有类属性动态添加新特性
Got it, let's figure out how to dynamically inject your SomeAttribute into the virtual properties of ClassA using System.Reflection.Emit. The key thing to note upfront is that you can't directly modify the metadata of an already loaded type in .NET—so we'll work around that by creating a derived class that overrides the virtual properties and adds the attribute there. Here's a complete walkthrough with code:
1. First, let's define the base types (filling in the code you mentioned)
Assuming your SomeAttribute and ClassA look something like this:
public class SomeAttribute : Attribute { public string Description { get; } public SomeAttribute(string description) => Description = description; } public class ClassA { public virtual string MyVirtualProperty { get; set; } public virtual int AnotherVirtualProp { get; set; } }
2. Core code to dynamically inject the attribute
This utility class will create a derived type of ClassA, override the target virtual property, and attach your SomeAttribute to the overridden property:
using System; using System.Reflection; using System.Reflection.Emit; public static class DynamicAttributeInjector { public static Type CreateClassADerivativeWithAttribute(string newTypeName, PropertyInfo targetVirtualProp, Attribute attributeToAdd) { // 1. Set up a dynamic assembly and module to host our new type var assemblyName = new AssemblyName($"Dynamic_{Guid.NewGuid()}"); var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule($"{assemblyName.Name}.dll"); // 2. Define the derived class (inherits from ClassA) var typeBuilder = moduleBuilder.DefineType( newTypeName, TypeAttributes.Public | TypeAttributes.Class, typeof(ClassA)); // Validate the target property is virtual and has get/set accessors var getMethod = targetVirtualProp.GetGetMethod(); var setMethod = targetVirtualProp.GetSetMethod(); if (getMethod == null || setMethod == null || !getMethod.IsVirtual || !setMethod.IsVirtual) { throw new ArgumentException("Target property must be a virtual property with both get and set accessors."); } // 3. Define the overridden property in our derived class var propertyBuilder = typeBuilder.DefineProperty( targetVirtualProp.Name, targetVirtualProp.Attributes, targetVirtualProp.PropertyType, Type.EmptyTypes); // 4. Attach the custom attribute to the property var attrConstructor = attributeToAdd.GetType().GetConstructor( attributeToAdd.GetType().GetProperties().Select(p => p.PropertyType).ToArray()); if (attrConstructor != null) { var attrArgs = attributeToAdd.GetType().GetProperties() .Select(p => p.GetValue(attributeToAdd)).ToArray(); propertyBuilder.SetCustomAttribute(new CustomAttributeBuilder(attrConstructor, attrArgs)); } // 5. Implement the overridden get method (calls base class get) var getMethodBuilder = typeBuilder.DefineMethod( getMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, targetVirtualProp.PropertyType, Type.EmptyTypes); var getIl = getMethodBuilder.GetILGenerator(); getIl.Emit(OpCodes.Ldarg_0); getIl.Emit(OpCodes.Call, getMethod); getIl.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(getMethodBuilder, getMethod); propertyBuilder.SetGetMethod(getMethodBuilder); // 6. Implement the overridden set method (calls base class set) var setMethodBuilder = typeBuilder.DefineMethod( setMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, typeof(void), new[] { targetVirtualProp.PropertyType }); var setIl = setMethodBuilder.GetILGenerator(); setIl.Emit(OpCodes.Ldarg_0); setIl.Emit(OpCodes.Ldarg_1); setIl.Emit(OpCodes.Call, setMethod); setIl.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(setMethodBuilder, setMethod); propertyBuilder.SetSetMethod(setMethodBuilder); // 7. Finalize and return the dynamic type return typeBuilder.CreateType(); } }
3. How to use this code
Here's a quick example to test the attribute injection:
// Get the virtual property we want to modify var targetProp = typeof(ClassA).GetProperty(nameof(ClassA.MyVirtualProperty)); // Create the attribute instance we want to inject var customAttr = new SomeAttribute("This was injected dynamically!"); // Generate our derived type var dynamicType = DynamicAttributeInjector.CreateClassADerivativeWithAttribute( "ClassA_WithInjectedAttr", targetProp, customAttr); // Verify the attribute was added successfully var instance = Activator.CreateInstance(dynamicType) as ClassA; var propWithAttr = dynamicType.GetProperty(nameof(ClassA.MyVirtualProperty)); var injectedAttr = propWithAttr.GetCustomAttribute<SomeAttribute>(); Console.WriteLine(injectedAttr?.Description); // Output: "This was injected dynamically!"
Key Notes to Remember
- You can't modify existing types: .NET runtime doesn't allow altering metadata of already loaded types, so creating a derived class is the only viable approach here.
- Virtual requirement: The target property must be marked
virtual—you can't override non-virtual properties in a derived class. - Attribute constructor handling: The code works with attributes that have constructor parameters. If your
SomeAttributeis parameterless, just adjust the constructor lookup logic to use the empty constructor.
内容的提问来源于stack exchange,提问作者Alex G

