Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an override method using Mono.Cecil?

Tags:

mono.cecil

I'm using Mono.Cecil to generate an assembly that contains a derived class that overrides a specific method in an imported base class. The override method is an 'implicit' override. The problem is that I cannot figure out how to designate it as an override.

I'm using the following code to create the override method.

    void CreateMethodOverride(TypeDefinition targetType,
        TypeDefinition baseClass, string methodName, MethodInfo methodInfo)
    {
        // locate the matching base class method, which may
        // reside in a different module
        MethodDefinition baseMethod = baseClass
            .Methods.First(method => method.Name.Equals(methodName));

        MethodDefinition newMethod = targetType.Copy(methodInfo);
        newMethod.Name = baseMethod.Name;
        newMethod.Attributes = baseMethod.Attributes;
        newMethod.ImplAttributes = baseMethod.ImplAttributes;
        newMethod.SemanticsAttributes = baseMethod.SemanticsAttributes;
        targetType.Methods.Add(newMethod);
    }

It is my understanding that an implicit override must have the same signature as the inherited method. Using the above code, when I view the resulting method in Reflector, the base class and the derived class methods have the exact same signature, namely "public virtual void f(int param)".

I've tried removing the explicit "virtual" attribute, but then the derived method ends up as "public void f(int param)'.

How do I get the derived method to have the correct "public override void f(int param)" signature?

NOTE: I have an extension method ("TypeDefinition.Copy") that clones a MethodInfo and returns a MethodDefinition by importing all of the referenced types, etc.

like image 284
John Holliday Avatar asked Nov 12 '11 02:11

John Holliday


2 Answers

For the benefit of other readers, here is the final result obtained by following JB's answer:

void CreateMethodOverride(TypeDefinition targetType,
    TypeDefinition baseClass, string methodName, MethodInfo methodInfo)
{
    MethodDefinition baseMethod = baseClass
        .Methods.First(method => method.Name.Equals(methodName));

    MethodDefinition newMethod = targetType.Copy(methodInfo);
    newMethod.Name = baseMethod.Name;

    // Remove the 'NewSlot' attribute
    newMethod.Attributes = baseMethod.Attributes & ~MethodAttributes.NewSlot;

    // Add the 'ReuseSlot' attribute
    newMethod.Attributes |= MethodAttributes.ReuseSlot;

    newMethod.ImplAttributes = baseMethod.ImplAttributes;
    newMethod.SemanticsAttributes = baseMethod.SemanticsAttributes;
    targetType.Methods.Add(newMethod);
}
like image 111
John Holliday Avatar answered Nov 13 '22 12:11

John Holliday


In your base class, let's say you generate the following method:

public virtual void f(int);

You have to make sure that it has the flag IsVirtual set to true. You also have to make sure that it has the flag IsNewSlot = true, to make sure that it has a new slot in the virtual method table.

Now, for the overridden methods, you want to generate:

public override void f(int);

To do so, you also need to have the method to be IsVirtual, but also to tell it that it's not a new virtual method, but that it implicitly overrides another, so you have to make it .IsReuseSlot = true.

And because you're using implicit overriding, you also have to make sure both methods are .IsHideBySig = true.

With that all set, you should have a proper overriding method.

like image 16
Jb Evain Avatar answered Nov 13 '22 12:11

Jb Evain