2016-04-25 2 views
0

У меня есть аспект PostSharp (реализованный ниже как AutoData) применительно к методу испытаний, как например:Как определить метод сплетения?

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

Как вы можете видеть, результат MethodBase.GetCurrentMethod возвращается в соткан тело. Я хотел бы, чтобы вместо того, чтобы извлечь (родительский) целевой метод, что аспект сотканный, в основном эквивалент:

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

Но в родовом, статическом способе, как то, что MethodBase.GetCurrentMethod обеспечивает.

Возможно ли это?

ответ

1

Само по себе невозможно получить исходный метод из кода во время выполнения.

Однако вы можете использовать аспекты для улучшения методов, в которых вам нужна эта информация, и запомнить, в каком методе вы находитесь в (потоковой) статической переменной стека.

Концептуально следующий код использует AssemblyLevelAspect, который усиливает все методы, из которых вы называете CurrentMethodService.Get() с внутренним MethodLevelAspect, который выталкивает текущий метод в стеке, когда метод выполняется и выскакивает, когда метод выхода.

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

Чтобы использовать этот аспект, просто примените его к сборке.

[assembly: CurrentMethodPolicy] 

Приятным побочным эффектом этого подхода является то, что поиск метода довольно быстр.

Обратите внимание, что вы не должны использовать CurrentMethodServices.Get() по любым другим аспектам, только в расширенном коде.

Кроме того, установка наследования атрибута на Multicast заставляет PostSharp применять аспект при ссылках на сборки, поэтому его нужно применять только в сборке, которая объявляет аспект.

Последнее, CurrentMethodServices.Get() не будет работать, если оно используется в проекте, который не использует PostSharp.

+0

WOW ... извините за задержку в ответе на это. Я так и не получил уведомление. Очень приятная работа. :) –

Смежные вопросы