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