2011-11-12 15 views
10

Estoy usando Mono.Cecil para generar un ensamblado que contiene una clase derivada que anula un método específico en una clase base importada. El método de anulación es una anulación "implícita". El problema es que no puedo encontrar la manera de designarlo como una anulación.¿Cómo crear un método de anulación usando Mono.Cecil?

Estoy usando el siguiente código para crear el método de anulación.

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

Tengo entendido que una anulación implícita debe tener la misma firma que el método heredado. Usando el código anterior, cuando veo el método resultante en Reflector, la clase base y los métodos de clase derivados tienen exactamente la misma firma, a saber, "void virtual público f (int param)".

He intentado quitar el atributo explícito "virtual", pero entonces el método derivado termina como "(int param)'.

¿Cómo puedo obtener el método derivado de tener la correcta public void f" public override void f (int param)" firma

NOTA:? tengo un método de extensión ("TypeDefinition.Copy") que se clona un MethodInfo y devuelve un MethodDefinition mediante la importación de todos los tipos de referencia, etc.

Respuesta

10

En su clase base, supongamos que genera el siguiente método:

public virtual void f(int); 

Debes asegurarte de que tiene la bandera IsVirtual establecida en verdadero. También debe asegurarse de que tiene la bandera IsNewSlot = true, para asegurarse de que tenga una nueva ranura en el virtual method table.

Ahora, por los métodos sobrescritos, que desea generar:

public override void f(int); 

Para ello, también es necesario tener el método a ser IsVirtual, sino también para decirle que no es un nuevo método virtual , pero que implícitamente reemplaza a otro, por lo que debe hacerlo .IsReuseSlot = true.

Y como está utilizando la anulación implícita, también debe asegurarse de que ambos métodos sean .IsHideBySig = true.

Con todo eso configurado, debe tener un método de anulación adecuado.

+0

Gracias por la info - exactamente lo que necesitaba. Por alguna razón, no recibí una notificación por correo electrónico de SO o del grupo Mono-Cecil. Lo siento por preguntar a través de múltiples canales! –

+0

¡No hay problema, nos alegramos de haber encontrado una solución a su problema! –

7

Para el beneficio de otros lectores, aquí está el resultado final obtenido siguiendo la respuesta de JB:

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