2011-11-12 9 views
10

Sto usando Mono.Cecil per generare un assembly che contiene una classe derivata che sostituisce un metodo specifico in una classe base importata. Il metodo di override è un override "implicito". Il problema è che non riesco a capire come definirlo come un override.Come creare un metodo di override utilizzando Mono.Cecil?

Sto usando il seguente codice per creare il metodo di sostituzione.

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

È a mia conoscenza che un override implicito deve avere la stessa firma del metodo ereditato. Usando il codice sopra, quando visualizzo il metodo risultante in Reflector, la classe base ei metodi della classe derivata hanno la stessa identica firma, cioè "public virtual void f (int param)".

Ho provato a rimuovere l'attributo esplicito "virtuale", ma poi il metodo derivato finisce come "public void f (int param)'.

Come faccio a ottenere il metodo derivato di avere la giusta" public override void f (int param)" firma

NOTA:? ho una metodo di estensione ("TypeDefinition.Copy"), che clona un MethodInfo e restituisce un MethodDefinition importando tutti i tipi di riferimento, ecc

risposta

10

Nella tua classe base, supponiamo tu generi il seguente metodo:

public virtual void f(int); 

Devi assicurarti che la bandiera IsVirtual sia impostata su true. Devi anche assicurarti che abbia la bandiera IsNewSlot = true, per assicurarti che abbia un nuovo slot nello virtual method table.

Ora, per i metodi override, si desidera generare:

public override void f(int); 

Per fare ciò, è anche bisogno di avere il metodo per essere IsVirtual, ma anche per dirgli che non è un nuovo metodo virtuale , ma che implicitamente sovrascrive un altro, quindi devi farlo .IsReuseSlot = true.

E poiché si sta eseguendo l'override implicito, è necessario assicurarsi che entrambi i metodi siano .IsHideBySig = true.

Con tutto ciò impostato, è necessario disporre di un metodo di sovrascrittura corretto.

+0

Grazie per le informazioni - esattamente quello che mi serviva. Per qualche motivo, non ho ricevuto una notifica via email da SO o dal gruppo Mono-Cecil. Ci scusiamo per aver chiesto attraverso più canali! –

+0

Nessun problema, siamo contenti di aver trovato una soluzione al tuo problema! –

7

A beneficio di altri lettori, ecco il risultato finale ottenuto seguendo la risposta di 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); 
} 
Problemi correlati