| Severity | Warning |
| Reported by | PostSharp |
| Message | The advice "<Advice>" is applied to the abstract method "<Method>". PostSharp gives the method an implementation that throws NotSupportedException, unless another aspect implements the method, so the advice gets this exception when it proceeds, and the overrides of the method in derived classes are not intercepted. If the aspect is applied by multicasting, set the AttributeTargetMemberAttributes property of the aspect, or the TargetMemberAttributes property of its MulticastAttributeUsage, to MulticastAttributes.NonAbstract. If an aspect provider or a pointcut selects the method, exclude abstract methods from its selection. |
Cause
A method interception advice, declared with OnMethodInvokeAdvice in a composite aspect such as a MethodLevelAspect, can be applied to an abstract method of the current project, by multicasting, by an IAspectProvider or by a pointcut. PostSharp then gives the abstract method an implementation, which the advice intercepts. This rarely does what you expect:
- Calls to the method are dispatched to the overrides of the derived classes, which PostSharp does not intercept, so the advice does not run.
- When the advice runs, for example when no derived class overrides the method, the implementation that it proceeds to throws NotSupportedException, unless another aspect implements the method.
PostSharp reports this warning on the abstract method. <Advice> is the advice method of the aspect.
In the following example, the [Trace] aspect is multicast to the methods of the abstract class Shape, including the abstract GetArea method. The output shows that the call to Rectangle.GetArea is not intercepted.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Extensibility;
using PostSharp.Serialization;
namespace Errors.LA0254_Error;
[PSerializable]
[MulticastAttributeUsage( MulticastTargets.Method )]
public class TraceAttribute : MethodLevelAspect
{
[OnMethodInvokeAdvice]
public void OnInvoke( MethodInterceptionArgs args )
{
Console.WriteLine( $"Calling {args.Method.DeclaringType!.Name}.{args.Method.Name}." );
args.Proceed();
}
}
[Trace]
public abstract class Shape
{
// The aspect is multicast to this abstract method, and not to its overrides.
public abstract int GetArea();
public string Describe() => $"{this.GetType().Name} with an area of {this.GetArea()}";
}
public class Rectangle : Shape
{
private readonly int width;
private readonly int height;
public Rectangle( int width, int height )
{
this.width = width;
this.height = height;
}
public override int GetArea() => this.width * this.height;
}
public static class Program
{
public static void Main()
{
Shape shape = new Rectangle( 3, 4 );
Console.WriteLine( shape.Describe() );
}
}
warning LA0254: LA0254_Error.cs(25,25): The advice "Errors.LA0254_Error.TraceAttribute.OnInvoke(PostSharp.Aspects.MethodInterceptionArgs)" is applied to the abstract method "Errors.LA0254_Error.Shape.GetArea". PostSharp gives the method an implementation that throws NotSupportedException, unless another aspect implements the method, so the advice gets this exception when it proceeds, and the overrides of the method in derived classes are not intercepted. If the aspect is applied by multicasting, set the AttributeTargetMemberAttributes property of the aspect, or the TargetMemberAttributes property of its MulticastAttributeUsage, to MulticastAttributes.NonAbstract. If an aspect provider or a pointcut selects the method, exclude abstract methods from its selection.
Calling Shape.Describe.
Rectangle with an area of 12
Resolution
Exclude the abstract methods from the targets of the advice:
- When the aspect is applied by multicasting, set the AttributeTargetMemberAttributes property of the aspect, or the TargetMemberAttributes property of its MulticastAttributeUsageAttribute, to NonAbstract.
- When an aspect provider or a pointcut selects the method, skip the abstract methods in its selection.
To intercept the overrides, apply the aspect to the derived classes, for example by setting the AttributeInheritance property of the aspect to Multicast.
In the following example, the [Trace] aspect skips the abstract GetArea method and is inherited by Rectangle, so the override of GetArea is intercepted.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Extensibility;
using PostSharp.Serialization;
namespace Errors.LA0254_Fixed;
[PSerializable]
[MulticastAttributeUsage( MulticastTargets.Method )]
public class TraceAttribute : MethodLevelAspect
{
[OnMethodInvokeAdvice]
public void OnInvoke( MethodInterceptionArgs args )
{
Console.WriteLine( $"Calling {args.Method.DeclaringType!.Name}.{args.Method.Name}." );
args.Proceed();
}
}
// The aspect skips the abstract method, and is inherited by the overrides of the derived classes.
[Trace( AttributeTargetMemberAttributes = MulticastAttributes.NonAbstract, AttributeInheritance = MulticastInheritance.Multicast )]
public abstract class Shape
{
public abstract int GetArea();
public string Describe() => $"{this.GetType().Name} with an area of {this.GetArea()}";
}
public class Rectangle : Shape
{
private readonly int width;
private readonly int height;
public Rectangle( int width, int height )
{
this.width = width;
this.height = height;
}
public override int GetArea() => this.width * this.height;
}
public static class Program
{
public static void Main()
{
Shape shape = new Rectangle( 3, 4 );
Console.WriteLine( shape.Describe() );
}
}
Calling Shape.Describe.
Calling Rectangle.GetArea.
Rectangle with an area of 12
See Also
Reference
OnMethodInvokeAdvice
AttributeTargetMemberAttributes
MulticastAttributes
MulticastInheritance
Other Resources
Advice Methods
Adding Aspects to Multiple Declarations Using Attributes
Understanding Attribute Multicasting