Hoe een override-methode maken met behulp van Mono.Cecil?

Ik gebruik Mono.Cecil om een ​​assembly te genereren die een afgeleide klasse bevat die een specifieke methode in een geïmporteerde basisklasse overschrijft. De override-methode is een 'impliciete' overschrijving. Het probleem is dat ik er niet achter kan komen hoe ik het moet aanduiden als een opheffing.

Ik gebruik de volgende code om de override-methode te maken.

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

Ik heb begrepen dat een impliciete overschrijving dezelfde handtekening moet hebben als de overgeërfde methode. Als ik de bovenstaande code gebruik, als ik de resulterende methode in Reflector bekijk, hebben de basisklasse en de afgeleide klassemethoden exact dezelfde handtekening, namelijk "public virtual void f (int param)".

Ik heb geprobeerd het expliciete "virtuele" attribuut te verwijderen, maar dan komt de afgeleide methode uit als "public void f (int param)".

Hoe krijg ik de afgeleide methode om de juiste "public override void f (int param)" handtekening te hebben?

Opmerking: ik heb een uitbreidingsmethode ("TypeDefinition.Copy") die een MethodInfo klonen en een MethodDefinition retourneert door alle typen waarnaar wordt verwezen te importeren, enzovoort.

10

2 antwoord

In uw basisklasse kunt u stellen dat u de volgende methode genereert:

public virtual void f(int);

U moet ervoor zorgen dat de vlag IsVirtual op true is ingesteld. Je moet ook zorgen dat het de vlag IsNewSlot = true heeft, om er zeker van te zijn dat het een nieuw slot heeft in de tabel met virtuele methoden .

Nu wilt u voor de overschreven methoden genereren:

public override void f(int);

Om dit te doen, moet je ook de methode hebben om IsVirtual te zijn, maar ook om te vertellen dat het geen nieuwe virtuele methode is, maar dat het impliciet een ander overschrijft, dus je moet het .IsReuseSlot = true .

En omdat u impliciet overschrijft, moet u ook controleren of beide methoden .IsHideBySig = true zijn.

Met dat alles klaar, zou u een juiste overheersende methode moeten hebben.

10
toegevoegd
Geen probleem, blij dat we een oplossing voor uw probleem hebben gevonden!
toegevoegd de auteur Jb Evain, de bron
Bedankt voor de info - precies wat ik nodig had. Om de een of andere reden kreeg ik geen e-mailmelding van SO of de Mono-Cecil-groep. Sorry voor het vragen via meerdere kanalen!
toegevoegd de auteur John Holliday, de bron

Ten behoeve van andere lezers, hier is het eindresultaat verkregen door het volgen van het antwoord van 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);
}
7
toegevoegd