在编译时自动将方法注入 class
Automatically inject methods to a class on compile-time
基本上我想要的是:
如果我有这样的 class 定义:
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 应该可以做到这一点,但不知道该怎么做。我看过的所有方面属性都只是修改现有的方法,这不是我想要的。我想为每个方法创建一个新的注入方法。
目前无法使用 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。
基本上我想要的是:
如果我有这样的 class 定义:
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 应该可以做到这一点,但不知道该怎么做。我看过的所有方面属性都只是修改现有的方法,这不是我想要的。我想为每个方法创建一个新的注入方法。
目前无法使用 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。