反射发出:如何转换属性实例CustomAttributeBuilder或一个CustomAttrib

2019-08-20 15:45发布

我提出,建立在此基础上实现的接口接口的代理类发电机类。

看到我后上建立基于接口的代理类没有实现它 。

我熟悉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]);

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

Answer 1:

这不是一般的解决方案,但如果你愿意来约束你那些参数构造函数和读/写属性和字段支持的属性将工作

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


Answer 2:

谢谢乔,
我找到了Expression的解决方案属性生成器 ,感谢您的输入。
我愿意工作有点困难,现在让其他开发者更容易使用我的代理服务器 。

我希望它可以更容易,如果我有属性的情况下,为什么我不能使用它的值并应用属性?

如果您有没有一个解决办法Expression ,我很想听到它。

这里是我的解决方案Expression基于属性生成器 :

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;
}


Answer 3:

如果我理解正确的问题,这应在自定义属性添加到生成的类型

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


文章来源: Reflection Emit: how to Convert Attribute instance to CustomAttributeBuilder or CustomAttributeData