如何确定编织方法?
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 的项目中使用时无法正常工作。
我有一个 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 的项目中使用时无法正常工作。