后置方面执行的顺序

本文关键字:顺序 执行 方面 | 更新日期: 2023-09-27 18:09:47

好的,这可能会很长。我想做两件事:

  • 我想有一个类,实现一个接口通过持有另一个类的实例,每个调用路由到。

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

在自己的作品上做这两件事很棒。将它们结合起来似乎只能在一个执行顺序中工作,正如Murphy所说,这是错误的(至少对我来说)。

我想首先注入组合,这样所有调用的拦截也会拦截那些先前注入的调用。

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();
    }
  }
}

我试图通过

来影响这两个方面的执行顺序
  • AspectRoleDependency,使拦截器依赖于首先运行的编写器

  • AspectPriority,也使作曲器优先运行

因为测试总是产生

TEST #1
CALL remote implemented
TEST #2
Intercepted before
CALL local implemented
Intercepted after

它显然不起作用。你知道为什么我的执行命令没有改变吗?是我做错了什么,还是我错过了文档中的某个细节?如何拦截组合注入的方法呢?

后置方面执行的顺序

以目前的情况和你目前的设置,你无法达到你想要的结果。

问题在于Postsharp是如何工作的:它在一步中完成IL波,并且它只将InterceptAspect应用于在原始编译时存在的方法,因此它看不到ComposeAspect添加的新接口实现。

所以没有接受或提供角色,优先级或其他配置的顺序在这里有帮助。

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

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

在这种情况下,日志逻辑将直接添加到TestImpl中,所以这些方法将包含日志记录,当它将被组合到你的Test类中。

或者如果你不标记每个实现,你可以把你的方面放在接口本身:

[InterceptAspect(AttributeInheritance = MulticastInheritance.Multicast)]
interface ITest
{
   void Call();
}