2011-11-12 18 views
10

Używam Mono.Cecil do generowania zespołu, który zawiera klasy pochodnej, który przesłonił określonej metody w zaimportowanej klasie bazowej. Metoda przesłaniania jest "niejawnym" nadpisaniem. Problem polega na tym, że nie potrafię określić, jak to nazwać nadpisaniem.Jak utworzyć metodę zastępowania przy użyciu Mono.Cecil?

Korzystam z następującego kodu, aby utworzyć metodę zastępowania.

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

Rozumiem, że domniemane przesłanianie musi mieć ten sam podpis co metoda odziedziczona. Korzystając z powyższego kodu, gdy wyświetlam wynikową metodę w Reflectorze, klasa bazowa i metody klasy pochodnej mają dokładnie tę samą sygnaturę, a mianowicie "publiczny wirtualny void f (int param)".

Próbowałem usunięcie wyraźny „wirtualny” atrybut, ale to metoda pochodzi kończy się jako „public void f (int param)”.

Jak mogę uzyskać metoda pochodzi mieć prawidłowy” override void f (int param)”podpis

UWAGA: mam metodę rozszerzenia («TypeDefinition.Copy»), które klonów MethodInfo i zwraca MethodDefinition poprzez importowanie wszystkich przywoływanych typów itd

Odpowiedz

10

W swojej klasie bazowej powiedzmy, że generujesz następującą metodę:

public virtual void f(int); 

Musisz upewnić się, że ma on flagę IsVirtual ustawioną na true. Musisz również upewnić się, że ma flagę IsNewSlot = true, aby upewnić się, że ma nowy slot w virtual method table.

Teraz do metod przesłoniętych, chcesz wygenerować:

public override void f(int); 

Aby to zrobić, trzeba także mieć metodę być IsVirtual, ale także, aby poinformować go, że nie jest to nowa metoda wirtualna , ale domyślnie przesłania inny, więc musisz go ustawić jako .IsReuseSlot = true.

A ponieważ używasz domyślnego nadpisywania, musisz również upewnić się, że obie metody są .IsHideBySig = true.

Przy tym ustawieniu powinieneś mieć odpowiednią metodę nadpisywania.

+0

Dzięki za info - dokładnie to, co potrzebne. Z jakiegoś powodu nie otrzymałem powiadomienia e-mail od SO lub grupy Mono-Cecil. Przepraszamy za pytanie przez wiele kanałów! –

+0

Bez problemu, cieszymy się, że znaleźliśmy rozwiązanie Twojego problemu! –

7

Z korzyścią dla innych czytelników, tutaj jest ostateczny wynik uzyskany przez następującą odpowiedź 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); 
} 
Powiązane problemy