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

时间:2013-04-09 07:24:37

标签: c# reflection reflection.emit

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

请参阅Build a Proxy class based on Interface without implementing it上的帖子。

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

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

例如:

开发人员可以将其作为值传递: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]);

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

3 个答案:

答案 0 :(得分:4)

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

,那么它将起作用。
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<Action> exp)
{
    //extract ConstructorInfo from exp
    //extract ParameterValues from exp
    //extract Attribute Type from exp

    return new CustomAttributeBuilder(ConstructorInfo, ParameterValues);
}

答案 1 :(得分:1)

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

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

如果您的解决方案没有Expression,我很乐意听到。

以下是基于Attribute BuilderExpression我的解决方案:

private CustomAttributeBuilder GetCustumeAttributeBuilder(Expression<Func<Attribute>> attributeExpression)
{
    ConstructorInfo constructor = null;
    List<object> constructorArgs = new List<object>();
    List<PropertyInfo> namedProperties = new List<PropertyInfo>();
    List<object> propertyValues = new List<object>();
    List<FieldInfo> namedFields = new List<FieldInfo>();
    List<object> fieldValues = new List<object>();

    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<MemberAssignment> 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<object> constructorArgs)
{
    foreach (Expression arg in expression.Arguments)
    {
        LambdaExpression lambda = Expression.Lambda(arg);
        object value = lambda.Compile().DynamicInvoke();
        constructorArgs.Add(value);
    }
    return expression.Constructor;
}

答案 2 :(得分:0)

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

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