Reflection Emit: how to Convert Attribute instance to CustomAttributeBuilder or CustomAttributeData

c#, reflection, reflection.emit

Solution

This is not a general solution, but will work if you are willing to constrain the attributes you support to those with parameterless constructors and Read/Write Properties and Fields

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

To do a general solution, you could use expressions. That is more complicated, but would allow syntax like:

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

Parsing the expression to extract the constructor info and the parameters would be the complex part, but it can be done.

CustomAttributeBuilder BuildCustomAttribute(Expression<Action> exp)
{
    //extract ConstructorInfo from exp
    //extract ParameterValues from exp
    //extract Attribute Type from exp

    return new CustomAttributeBuilder(ConstructorInfo, ParameterValues);
}

Problem

I made a generator class that build a proxy class based on interface which implement the interface. See my post on Build a Proxy class based on Interface without implementing it. I'm familiar with `CustomAttributeData.GetCustomAttributes(MemberInfo target)`, I used it when I read the Interface's members and succeed to import them to the proxy. I want to inject additional attributes to generated class in run-time. I'm asking for attributes instances to inject them into the proxy. For example: A developer can pass this as a value: `new ObsoleteAttribute("Demo", true)`, (it has an empty constructor, but properties are read only), and I want to convert it to: ``` return new CustomAttributeBuilder( attribute.GetType().GetConstructor(Type[] {typeof (string), typeof (bool)}), new object[] {"Demo", true}, new FieldInfo[0], new object[0]); ``` Remember, I can't tell what is given.

Original source