在编译时自动将方法注入类

时间:2017-05-30 15:23:29

标签: c# postsharp

基本上,我想要的是:

如果我有这样的课程定义:

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应该可行,但无法弄清楚如何操作。我看过的所有方面属性都只是修改现有方法,这不是我想要的。我想为每种方法创建一个新的注入方法。

1 个答案:

答案 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。