在编译时自动将方法注入 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。