如何确定编织方法?

How Can I Determine the Weaved Method?

我有一个 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 提供的那样是一种通用的静态方式。

这可能吗?

本身无法在运行时从代码中获取原始方法。

但是,您可以使用方面来增强您需要此信息的方法,并记住您在(线程)静态堆栈变量中的方法。

从概念上讲,以下代码使用 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 的项目中使用时无法正常工作。