订购Postsharp Aspects执行

nvo*_*igt 12 c# aop postsharp visual-studio-2012

好吧,这可能会变得冗长.我想做两件事:

  • 我想通过保存每个调用被路由到的另一个类的实例来创建一个实现接口的类.

  • 我还想拦截所有方法调用并做一些事情.

两个人都做得很好.将它们组合起来似乎只能在一个执行顺序中起作用,而且正如墨菲所说的那样,它是错误的(至少对我而言).

我想注入组成第一,让所有来电的拦截也将拦截那些先前注入.

namespace ConsoleApplication13
{
  using System;
  using System.Reflection;

  using PostSharp;
  using PostSharp.Aspects;
  using PostSharp.Aspects.Dependencies;
  using PostSharp.Extensibility;

  [Serializable]
  [ProvideAspectRole("COMPOSER")]
  public sealed class ComposeAspectAttribute : CompositionAspect
  {
    [NonSerialized]
    private readonly Type interfaceType;

    private readonly Type implementationType;

    public ComposeAspectAttribute(Type interfaceType, Type implementationType)
    {
      this.interfaceType = interfaceType;
      this.implementationType = implementationType;
    }

    // Invoked at build time. We return the interface we want to implement. 
    protected override Type[] GetPublicInterfaces(Type targetType)
    {
      return new[] { this.interfaceType };
    }

    // Invoked at run time. 
    public override object CreateImplementationObject(AdviceArgs args)
    {
      return Activator.CreateInstance(this.implementationType);
    }
  }

  [Serializable]
  [ProvideAspectRole("INTERCEPTOR")]
  [MulticastAttributeUsage(MulticastTargets.Method)]
  [AspectRoleDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, "COMPOSER")]
  public sealed class InterceptAspectAttribute : MethodInterceptionAspect
  {
    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
    {
      base.CompileTimeInitialize(method, aspectInfo);

      // Warning in VS output
      Message.Write(method, SeverityType.Warning, "XXX", "Method: " + method.Name);
    }

    public override void OnInvoke(MethodInterceptionArgs args)
    {
      Console.WriteLine("Intercepted before");
      args.Proceed();
      Console.WriteLine("Intercepted after");
    }
  }

  interface ITest
  {
    void Call();
  }

  class TestImpl : ITest
  {
    public void Call()
    {
      Console.WriteLine("CALL remote implemented");
    }
  }

  [InterceptAspect(AspectPriority = 1)]
  [ComposeAspect(typeof(ITest), typeof(TestImpl), AspectPriority = 2)]
  class Test
  {
    // this should, after compilation, have all methods of ITest, implemented through an instance of TestImpl, which get intercepted before TestImpl is called

    public void CallLocalImplementedTest()
    {
      Console.WriteLine("CALL local implemented");
    }
  }


  class Program
  {
    static void Main()
    {
      var test = new Test();

      ITest t = Post.Cast<Test, ITest>(test);

      Console.WriteLine("TEST #1");
      t.Call();

      Console.WriteLine("TEST #2");
      test.CallLocalImplementedTest();

      Console.ReadLine();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我试图通过以下方式影响这两个方面的执行顺序

  • AspectRoleDependency,使拦截器依赖于首先运行的composer

  • AspectPriority,也让作曲家先跑.

因为测试总是屈服

TEST #1
CALL remote implemented

TEST #2
Intercepted before
CALL local implemented
Intercepted after
Run Code Online (Sandbox Code Playgroud)

它显然不起作用.你有一个线索,为什么我的执行命令没有改变?我做错了什么,我是否错过了文档中的细节?我还能做些什么来拦截我的注射成分的方法呢?

nem*_*esv 2

以当前的方面和您当前的设置,您无法实现您想要的结果。

问题在于 Postsharp 的工作方式:它一步完成 IL 操作,并且仅将 应用于原始编译时存在的InterceptAspect方法,因此它看不到随.ComposeAspect

因此,接受或提供角色、优先级或其他配置的排序在这里没有帮助。

一种解决方法是InterceptAspect在注入的TestImpl类上添加:

[InterceptAspect]
class TestImpl : ITest
  {
    public void Call()
    {
      Console.WriteLine("CALL remote implemented");
    }
  }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,将直接添加日志记录逻辑TestImpl,因此这些方法在将其组合到您的Test类中时将包含日志记录。

或者,如果您不标记每个实现,您可以将方面放在接口本身上:

[InterceptAspect(AttributeInheritance = MulticastInheritance.Multicast)]
interface ITest
{
   void Call();
}
Run Code Online (Sandbox Code Playgroud)