I am trying to generate a new set of wcf interfaces based on existing interfaces. I am using the Reflection.Emit namespace to accomplish this. My problem is how to copy the old custom attributes from one method to the new method. Every example I have seen of SetCustomAttributes() requires knowing the attribute type beforehand. I need to discover the attribute type at runtime. Any thoughts?
Asked
Active
Viewed 2,942 times
4 Answers
7
The answer you (frjames) posted is close, but doesn't account for property initializers like...
[ServiceBehavior(Name="ServiceName")]
However, the idea of converting CustomAttributeData to a CustomAttributeBuilder for use in Reflection.Emit is right on.
I ended up having to do this for an open source project (Autofac) and came up with this extension method:
public static CustomAttributeBuilder ToAttributeBuilder(this CustomAttributeData data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
var constructorArguments = new List<object>();
foreach (var ctorArg in data.ConstructorArguments)
{
constructorArguments.Add(ctorArg.Value);
}
var propertyArguments = new List<PropertyInfo>();
var propertyArgumentValues = new List<object>();
var fieldArguments = new List<FieldInfo>();
var fieldArgumentValues = new List<object>();
foreach (var namedArg in data.NamedArguments)
{
var fi = namedArg.MemberInfo as FieldInfo;
var pi = namedArg.MemberInfo as PropertyInfo;
if (fi != null)
{
fieldArguments.Add(fi);
fieldArgumentValues.Add(namedArg.TypedValue.Value);
}
else if (pi != null)
{
propertyArguments.Add(pi);
propertyArgumentValues.Add(namedArg.TypedValue.Value);
}
}
return new CustomAttributeBuilder(
data.Constructor,
constructorArguments.ToArray(),
propertyArguments.ToArray(),
propertyArgumentValues.ToArray(),
fieldArguments.ToArray(),
fieldArgumentValues.ToArray());
}
That one accounts for all the ways to initialize the attribute.

Travis Illig
- 23,195
- 2
- 62
- 85
-
I realise this is old but this is a great answer and saved me a bunch of time recently however I did come across a small issue with this as well. If you have an attribute that has a `params SomeType[] constructor` argument (I'm not sure if params makes a difference or not) then this fails because for some reason the constructor argument value is held as `ReadOnlyCollection
` which cannot be converted to a `SomeType[]` by the CustomAttributeBuilder constructor. – rcarrington Dec 07 '16 at 16:21 -
Is not working in .Net Core `'CustomAttributeNamedArgument' does not contain a definition for 'MemberInfo'` – Alex Zhukovskiy Jan 07 '17 at 10:29
-
The question/answer here is six years old now and is for full .NET. .NET Core reflection is very different. – Travis Illig Jan 07 '17 at 17:12
-
I've added an amended version to work with .Net Core @AlexZhukovskiy – James Ellis-Jones May 30 '17 at 11:09
3
Here is the answer I came up with after some more research.
CustomAttributeBuilder ct = AddAttributesToMemberInfo(methodInfo);
if (ct != null)
{
methodBuilder.SetCustomAttribute(ct);
}
CustomAttributeBuilder AddAttributesToMemberInfo(MemberInfo oldMember)
{
CustomAttributeBuilder ct = null;
IList<CustomAttributeData> customMethodAttributes = CustomAttributeData.GetCustomAttributes(oldMember);
foreach (CustomAttributeData att in customMethodAttributes)
{
List<object> namedFieldValues = new List<object>();
List<FieldInfo> fields = new List<FieldInfo>();
List<object> constructorArguments = new List<object>();
foreach (CustomAttributeTypedArgument cata in att.ConstructorArguments)
{
constructorArguments.Add(cata.Value);
}
if (att.NamedArguments.Count > 0)
{
FieldInfo[] possibleFields = att.GetType().GetFields();
foreach (CustomAttributeNamedArgument cana in att.NamedArguments)
{
for (int x = 0; x < possibleFields.Length; x++)
{
if (possibleFields[x].Name.CompareTo(cana.MemberInfo.Name) == 0)
{
fields.Add(possibleFields[x]);
namedFieldValues.Add(cana.TypedValue.Value);
}
}
}
}
if (namedFieldValues.Count > 0)
{
ct = new CustomAttributeBuilder(att.Constructor, constructorArguments.ToArray(), fields.ToArray(), namedFieldValues.ToArray());
}
else
{
ct = new CustomAttributeBuilder(att.Constructor, constructorArguments.ToArray());
}
}
return ct;
}

frjames
- 81
- 1
- 6
1
The code from Travis Illig needs amendment as below to work with .Net Core:
foreach (var namedArg in data.NamedArguments)
{
string argName = namedArg.MemberName;
var fi = data.AttributeType.GetField(argName);
var pi = data.AttributeType.GetProperty(argName);

James Ellis-Jones
- 3,042
- 21
- 13
0
try this:
MethodInfo mi;
//...
object[] custAttribs = mi.GetCustomAttributes(false);
foreach (object attrib in custAttribs)
attrib.GetType();
i assume you have MethodInfo for your methods

Andrey
- 59,039
- 12
- 119
- 163