| Severity | Warning |
| Reported by | PostSharp |
| Message | For better runtime performance, avoid a virtual call or a call to another assembly from the advice "<Advice>" to the method "<Method>": PostSharp cannot analyze this method, so it disables the optimizations of the advice. Make the method non-virtual, or do not pass it a parameter of type "<AdviceArgsType>". |
Cause
At build time, PostSharp analyzes the body of each advice, such as OnEntry, to find which properties of its AdviceArgs parameter it uses. It then generates code that initializes only these properties, which makes the aspect faster at run time. When the advice passes its arguments to another method of the same assembly, PostSharp analyzes that method too.
PostSharp cannot analyze the called method, and reports LA0108, when the advice passes its arguments to:
- a virtual method that is not sealed, in a class that is not sealed, because a derived class can override it with code that uses other properties;
- an instance method of another assembly;
- a delegate created from a virtual method.
PostSharp then disables all the optimizations of the advice. The aspect still works, so this is a warning, but the code generated for each target method initializes every property of the arguments.
<AdviceArgsType> is always AdviceArgs, the base class of all advice arguments, such as MethodExecutionArgs.
The warning is reported on the call. In the following example, the OnEntry advice passes its arguments to the virtual WriteEntry method.
using System;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0108_Error;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args )
{
// The advice passes its arguments to a virtual method, which a derived aspect could override.
this.WriteEntry( args );
}
protected virtual void WriteEntry( MethodExecutionArgs args )
{
Console.WriteLine( $"Entering {args.Method.Name}." );
}
}
public class OrderService
{
[Log]
public void PlaceOrder() => Console.WriteLine( "Order placed." );
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder();
}
}
warning LA0108: LA0108_Error.cs(13,9): For better runtime performance, avoid a virtual call or a call to another assembly from the advice "Errors.LA0108_Error.LogAttribute.OnEntry(PostSharp.Aspects.MethodExecutionArgs)" to the method "Errors.LA0108_Error.LogAttribute.WriteEntry(PostSharp.Aspects.MethodExecutionArgs)": PostSharp cannot analyze this method, so it disables the optimizations of the advice. Make the method non-virtual, or do not pass it a parameter of type "PostSharp.Aspects.AdviceArgs".
Resolution
- Make the called method non-virtual, for example
private, or seal it. - When the method is in another assembly, or must stay virtual, read the properties that it needs in the advice and pass their values instead of the advice arguments.
In the following example, WriteEntry is private, so PostSharp analyzes it with the advice.
using System;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0108_Fixed;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args )
{
this.WriteEntry( args );
}
// The method is not virtual, so PostSharp can analyze how it uses the arguments of the advice.
private void WriteEntry( MethodExecutionArgs args )
{
Console.WriteLine( $"Entering {args.Method.Name}." );
}
}
public class OrderService
{
[Log]
public void PlaceOrder() => Console.WriteLine( "Order placed." );
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder();
}
}
Entering PlaceOrder.
Order placed.
See Also
Reference
AdviceArgs
MethodExecutionArgs
OnMethodBoundaryAspect
Other Resources