基本上,我想要的是:
如果我有这样的课程定义:
public class MyClass()
{
public int MyMethod()
{
return 42;
}
}
我想在编译时注入所有方法的不同副本。
所以实际的编译版本(例如)将如下所示:
public class MyClass()
{
public int MyMethod()
{
return 42;
}
// injected method ...
public int MyMethodInjected()
{
return MyMethod() * 2; // just an example
}
}
我知道使用类型属性使用PostSharp应该可行,但无法弄清楚如何操作。我看过的所有方面属性都只是修改现有方法,这不是我想要的。我想为每种方法创建一个新的注入方法。
答案 0 :(得分:2)
PostSharp Aspect Framework目前无法实现这一点,因为您无法为引入的方法命名。供参考,请考虑以下事项:
[DuplicateAspect]
public class TargetClass
{
public int MyMethod()
{
return 42;
}
}
// We want the aspect to apply to types and provide other aspects.
[PSerializable]
public class DuplicateAspect : TypeLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
Type targetType = (Type)targetElement;
foreach (MethodInfo method in targetType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
// For each public instance method declared in the target type, apply an aspect that duplicates a single method.
yield return new AspectInstance(targetType, new DuplicateSingle(method));
}
}
}
// We want the aspect to be instance-scoped and provide advices.
[PSerializable]
public class DuplicateSingle : IAspect, IInstanceScopedAspect, IAdviceProvider
{
private MethodInfo sourceMethod;
public Func<int> Method;
public DuplicateSingle(MethodInfo sourceMethod)
{
this.sourceMethod = sourceMethod;
}
public IEnumerable<AdviceInstance> ProvideAdvices(object targetElement)
{
Type targetType = (Type)targetElement;
FieldInfo field = typeof(DuplicateSingle).GetField(nameof(Method));
MethodInfo method = typeof(DuplicateSingle).GetMethod(nameof(IntroducedMethod));
// Provide import method advices, which stores delegate into a field of the aspect upon instance creation (remember - instance scoped aspect).
yield return new ImportMethodAdviceInstance(field, this.sourceMethod.Name, false, ImportMemberOrder.BeforeIntroductions);
// Provide introduce method advice, which introduces a stub calling the aspect method into the target class.
// PROBLEM: It's not possible to rename the method, hence this will fail.
yield return new IntroduceMethodAdviceInstance(method, PostSharp.Reflection.Visibility.Public, false, MemberOverrideAction.Fail);
}
public object CreateInstance(AdviceArgs adviceArgs)
{
return new DuplicateSingle(this.sourceMethod);
}
public void RuntimeInitializeInstance()
{
}
public int IntroducedMethod()
{
return this.Method() * 2;
}
}
引入的方法将始终与您提供给建议实例的方法信息相同(目前无法更改引入方法名称)。
由于动态引入方法没有更大的好处,我认为这不会被实现为PostSharp的有效用例。
我建议使用更低级别的IL重写工具,例如Mono CeCil。