PostSharp:调用基本方法时如何防止双方面调用?

PostSharp: How to prevent double aspect invoking when calling base method?

例如:

class BaseClass : IDisposable {
   [LogMethod]
   public BaseClass() {
   }

   [LogMethod] // This is OnMethodBoundaryAspect with MulticastInheritance.Strict
   public virtual void Dispose() { // overridden method
   }
}

class SubClass : BaseClass {
    public SubClass() : base() { // this doesn't lead to double LogMethod invoking
    }

    public override void Dispose() { // overriding method
      base.Func(); // this leads to double LogMethod invoking
    }
}

问题是 base.Func() 导致双方面调用。有可能避免这种情况吗?

不更改代码或对方面本身进行更改是不可能的。

原因是PostSharp转换了方法代码。它将对方面的调用添加到 BaseClass.Dispose 的方法主体和 SubClass.Dispose 的方法主体。由于 BaseClass.Dispose 调用 SubClass.Dispose,方面将同时执行。

要在从 SubClass.Dispose 调用 BaseClass.Dispose 时禁用方面,您需要将有关其调用者的信息传递给基本方法。在不更改代码(这会破坏方面的目的)的情况下,可以通过更改方面以使用 AsyncLocal[ThreadStatic] 在方面实例之间传递状态。

这可能是最好的方法。我只是忽略登录覆盖的方法。

    void IInstanceScopedAspect.RuntimeInitializeInstance() {
        IsEnabled = !IsOverridden( method, instance );
    }

    private static bool IsOverridden(MethodBase method, object instance) {
        if (method is MethodInfo method_) return instance.GetType().HasOverridingMethod( method_ );
        return false;
    }


    public static bool HasOverridingMethod(this Type type, MethodInfo baseMethod) {
        return type.GetOverridingMethod( baseMethod ) != null;
    }
    public static MethodInfo GetOverridingMethod(this Type type, MethodInfo baseMethod) {
        var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod;
        return type.GetMethods( flags ).FirstOrDefault( i => baseMethod.IsBaseMethodOf( i ) );
    }
    private static bool IsBaseMethodOf(this MethodInfo baseMethod, MethodInfo method) {
        return baseMethod.DeclaringType != method.DeclaringType && baseMethod == method.GetBaseDefinition();
    }