2016-04-25 11 views
0

Ich habe einen Postsharp Aspekt (im Folgenden als AutoData implementiert), die auf ein Testverfahren als solche:Wie kann ich die gewebte Methode ermitteln?

[Theory, AutoData(additionalTypes: typeof(MethodFormatter))] public void MethodFormatsAsExpected(FormatterFactory sut) { var name = MethodBase .GetCurrentMethod() .Name; // Resolves to "<MethodFormatsAsExpected>z__OriginalMethod" }

Wie Sie sehen können, ist das Ergebnis der MethodBase.GetCurrentMethod den spann Körper zurückkehrt. Ich möchte stattdessen die (übergeordnete) Zielmethode abzurufen, die der Aspekt gewoben hat, im Grunde das Äquivalent von:

var method = GetType() .GetMethod(nameof(MethodFormatsAsExpected)) .Name; // Returns "MethodFormatsAsExpected"

Aber in einem allgemeinen, statische Art und Weise wie das, was MethodBase.GetCurrentMethod bietet.

Ist das möglich?

Antwort

1

Es ist nicht möglich, die ursprüngliche Methode aus dem Code zur Laufzeit zu erhalten.

Sie können jedoch Aspekte verwenden, um Methoden zu verbessern, in denen Sie diese Informationen benötigen, und sich daran erinnern, in welcher Methode Sie sich in einer (Thread-) statischen Stapelvariablen befinden.

Konzeptionell der folgende Code verwendet eine AssemblyLevelAspect, die alle Methoden, von denen verbessert Sie CurrentMethodService.Get() mit einem internen MethodLevelAspect nennen, die eine aktuelle Methode in den Stapel schiebt, wenn das Verfahren ausgeführt wird, und öffnet es, wenn das Verfahren beendet wird.

public static class CurrentMethodServices 
{ 
    [ThreadStatic] 
    private static Stack<MethodBase> slots; 

    internal static Stack<MethodBase> Slots 
    { 
     get { return slots ?? (slots = new Stack<MethodBase>()); } 
    } 

    public static MethodBase Get() 
    { 
     return Slots.Peek(); 
    } 

    internal static void Enter(MethodBase slot) 
    { 
     Slots.Push(slot); 
    } 

    internal static void Exit() 
    { 
     Slots.Pop(); 
    } 
} 

[PSerializable] 
[MulticastAttributeUsage(MulticastTargets.Assembly, Inheritance = MulticastInheritance.Multicast)] 
public class CurrentMethodPolicy : AssemblyLevelAspect, IAspectProvider 
{ 
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement) 
    { 
     foreach (
      MethodUsageCodeReference methodRef in 
       ReflectionSearch.GetMethodsUsingDeclaration(typeof(CurrentMethodServices).GetMethod("Get", 
        BindingFlags.Public | BindingFlags.Static))) 
     { 
      if ((methodRef.Instructions & MethodUsageInstructions.Call | MethodUsageInstructions.CallVirtual) != 0) 
       yield return new AspectInstance(methodRef.UsingMethod, new MethodEnhancement()); 
     } 
    } 

    [PSerializable] 
    public class MethodEnhancement : IMethodLevelAspect 
    { 
     [PNonSerialized] 
     private MethodBase method; 

     public void RuntimeInitialize(MethodBase method) 
     { 
      this.method = method; 
     } 

     [OnMethodEntryAdvice] 
     [SelfPointcut] 
     public void OnMethodEntry(MethodExecutionArgs args) 
     { 
      CurrentMethodServices.Enter(this.method); 
     } 

     [OnMethodExitAdvice] 
     [SelfPointcut] 
     public void OnMethodExit(MethodExecutionArgs args) 
     { 
      CurrentMethodServices.Exit(); 
     } 
    } 
} 

Um diesen Aspekt zu verwenden, wenden Sie ihn einfach auf die Baugruppe an.

Ein schöner Nebeneffekt dieses Ansatzes ist, dass die Methode Lookup ziemlich schnell ist.

Beachten Sie, dass Sie nicht von anderen Aspektmethoden verwenden sollten, nur im erweiterten Code.

Wenn Sie die Aspektvererbung auf Multicast festlegen, wird PostSharp gezwungen, den Aspekt auf referenzierende Assemblys anzuwenden, sodass Sie ihn nur in der Assembly anwenden müssen, die den Aspekt deklariert.

Last, wird nicht funktionieren, wenn es in einem Projekt verwendet wird, das PostSharp nicht verwendet.

+0

WOW ... Entschuldigung für die Verzögerung bei der Reaktion darauf. Ich habe nie eine Benachrichtigung dafür erhalten. Sehr gute Arbeit. :) –

Verwandte Themen