Reflection Emit:如何将Attribute实例转换为CustomAttributeBuilder或CustomAttributeData

我创建了一个生成器类,它基于实现接口的接口构建代理类。

请参阅我在基于接口构建代理类的post而不实现它 。

我熟悉CustomAttributeData.GetCustomAttributes(MemberInfo target) ,当我读取Interface的成员并成功将它们导入代理时,我使用它。

我想在运行时向生成的类注入其他属性。 我要求将属性实例注入代理中。

例如:

开发人员可以将其作为值传递: new ObsoleteAttribute("Demo", true) ,(它有一个空构造函数,但属性是只读的),我想将其转换为:

 return new CustomAttributeBuilder( attribute.GetType().GetConstructor(Type[] {typeof (string), typeof (bool)}), new object[] {"Demo", true}, new FieldInfo[0], new object[0]); 

记住,我不知道给出了什么。

这不是一般解决方案,但如果您愿意将支持的属性约束到具有无参数构造函数和读/写属性和字段的属性,则可以使用它。

 CustomAttributeBuilder BuildCustomAttribute(System.Attribute attribute) { Type type = attribute.GetType(); var constructor = type.GetConstructor(Type.EmptyTypes); var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); var propertyValues = from p in properties select p.GetValue(attribute, null); var fieldValues = from f in fields select f.GetValue(attribute); return new CustomAttributeBuilder(constructor, Type.EmptyTypes, properties, propertyValues.ToArray(), fields, fieldValues.ToArray()); } 

要做一般解决方案,您可以使用表达式。 这更复杂,但允许语法如下:

 BuildCustomAttribute(() => new ObsoleteAttribute("Demo", true)); 

解析表达式以提取构造函数信息和参数将是复杂的部分,但它可以完成。

 CustomAttributeBuilder BuildCustomAttribute(Expression exp) { //extract ConstructorInfo from exp //extract ParameterValues from exp //extract Attribute Type from exp return new CustomAttributeBuilder(ConstructorInfo, ParameterValues); } 

谢谢乔,
由于您的输入,我确实在Attribute Builder中找到了Expression解决方案。
我现在愿意更努力地让其他开发人员更容易使用我的代理 。

我希望它可以更容易,如果我有属性实例,为什么我不能按原样使用它并应用属性?

如果你有一个没有Expression的解决方案,我很乐意听到它。

这是基于Attribute Builder的 Expression的解决方案:

 private CustomAttributeBuilder GetCustumeAttributeBuilder(Expression> attributeExpression) { ConstructorInfo constructor = null; List constructorArgs = new List(); List namedProperties = new List(); List propertyValues = new List(); List namedFields = new List(); List fieldValues = new List(); switch (attributeExpression.Body.NodeType) { case ExpressionType.New: constructor = GetConstructor((NewExpression)attributeExpression.Body, constructorArgs); break; case ExpressionType.MemberInit: MemberInitExpression initExpression = (MemberInitExpression)attributeExpression.Body; constructor = GetConstructor(initExpression.NewExpression, constructorArgs); IEnumerable bindings = from b in initExpression.Bindings where b.BindingType == MemberBindingType.Assignment select b as MemberAssignment; foreach (MemberAssignment assignment in bindings) { LambdaExpression lambda = Expression.Lambda(assignment.Expression); object value = lambda.Compile().DynamicInvoke(); switch (assignment.Member.MemberType) { case MemberTypes.Field: namedFields.Add((FieldInfo)assignment.Member); fieldValues.Add(value); break; case MemberTypes.Property: namedProperties.Add((PropertyInfo)assignment.Member); propertyValues.Add(value); break; } } break; default: throw new ArgumentException("UnSupportedExpression", "attributeExpression"); } return new CustomAttributeBuilder( constructor, constructorArgs.ToArray(), namedProperties.ToArray(), propertyValues.ToArray(), namedFields.ToArray(), fieldValues.ToArray()); } private ConstructorInfo GetConstructor(NewExpression expression, List constructorArgs) { foreach (Expression arg in expression.Arguments) { LambdaExpression lambda = Expression.Lambda(arg); object value = lambda.Compile().DynamicInvoke(); constructorArgs.Add(value); } return expression.Constructor; } 

如果我正确理解了这个问题,那么应该为生成的类型添加自定义属性

 public class CustomAttribute: System.Attribute { public CustomAttribute() { } } TypeBuilder typeBuilder = module.DefineType(...) 

….

 typeBuilder.SetCustomAttribute(new CustomAttributeBuilder( typeof(CustomAttribute).GetConstructor(Type.EmptyTypes), Type.EmptyTypes, new FieldInfo[0], new object[0]));