16

I can't figure how to add custom attribute to a method using Mono.Cecil The attributes that I would want to add is like this :

.custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) 

Does anyone know how to add custom attributes

method
  • 1,369
  • 3
  • 16
  • 29

3 Answers3

16

It's actually very easy.

ModuleDefinition module = ...;
MethodDefinition targetMethod = ...;
MethodReference attributeConstructor = module.Import(
    typeof(DebuggerHiddenAttribute).GetConstructor(Type.EmptyTypes));

targetMethod.CustomAttributes.Add(new CustomAttribute(attributeConstructor));
module.Write(...);
Jb Evain
  • 17,319
  • 2
  • 67
  • 67
  • 1
    @JbEvain +1 from me for developing that awesome library. I'm subscribed to your github changes feed so I know the work that still pours in step by step – sehe Dec 05 '11 at 19:22
  • 3
    @JbEvain what if we want to set some properties of custom attribute? – mohas Jun 01 '15 at 12:23
4

This is my take,

MethodDefinition methodDefinition = ...;
var module = methodDefinition.DeclaringType.Module;
var attr = module.Import(typeof (System.Diagnostics.DebuggerHiddenAttribute));

var attrConstructor = attr.Resolve().Constructors.GetConstructor(false, new Type[] {});
methodDefinition.CustomAttributes.Add(new CustomAttribute(attrConstructor));

I noticed Jb Evain's snippet is slightly different. I'm not sure whether that is because is because he's using a newer version of Cecil or because I'm wrong :)

In my version of Cecil, Import returns a TypeReference, not the constructor.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Cheers - I was stuck on 0.5.0 or earlier so I wouldn't jump to the conclusion :) – sehe Dec 05 '11 at 19:21
  • I've one final question guyz, : ILProcessor.Append( Instruction.Create(OpCodes.Newarr, )); what should the operand be ? , I've already add ldc instruction. – method Dec 05 '11 at 19:24
  • 1
    @user959615 It expects a TypeReference (to the element types of the array), so e.g. `Instruction.Create(OpCodes.Newarr, module.Import(typeof(Object))))` to create an new Object[] – sehe Dec 05 '11 at 19:51
2

I want to elaborate on Jb Evain's answer, about how to pass parameters to the attribute. For the sample, I used System.ComponentModel.BrowsableAttribute and passed the vlaue of browsable parameter to its constructor:

void AddBrowsableAttribute(
    ModuleDefinition module,
    Mono.Cecil.ICustomAttributeProvider targetMember, // Can be a PropertyDefinition, MethodDefinition or other member definitions
    bool browsable)
{
    // Your attribute type
    var attribType = typeof(System.ComponentModel.BrowsableAttribute);
    // Find your required constructor. This one has one boolean parameter.
    var constructor = attribType.GetConstructors()[0];
    var constructorRef = module.ImportReference(constructor);
    var attrib = new CustomAttribute(constructorRef);
    // The argument
    var browsableArg =
        new CustomAttributeArgument(
            module.ImportReference(typeof(bool)),
            browsable);
        attrib.ConstructorArguments.Add(browsableArg);
    targetMember.CustomAttributes.Add(attrib);
}

Also, named arguments can be added to Properties collection of the created CustomAttribute.

Mohammad Dehghan
  • 17,853
  • 3
  • 55
  • 72