| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot apply the aspect "<Aspect>" to "<Target>": aspects cannot be applied to a declaration of kind "<DeclarationKind>". Apply the aspect to a declaration of the source code instead. Code that selects the targets of an aspect, such as an IAspectProvider, can skip these declarations by checking MemberInfo.GetSemanticInfo().IsSelectable. |
Cause
The C# compiler implements some constructs of the source code with members that it generates: local functions and anonymous methods become methods with generated names, and async methods and iterators become state-machine types. PostSharp does not apply aspects to these declarations, whose IsSelectable property is false. <DeclarationKind> names the kind of the declaration, for example local function, anonymous method or compiler-generated method.
PostSharp reports LA0167 when an aspect reaches such a declaration:
- A custom attribute of an aspect is applied to a local function, which C# allows since version 9.
- An IAspectProvider provides an aspect for a member that it found by reflection, such as a method of a closure class or the
MoveNextmethod of a state machine. - A location-level aspect is applied to a parameter of a method that cannot receive aspects.
In the following example, the [Log] aspect is applied to the local function Describe. <Target> shows the name of the method that the compiler generated, and the message has no location in the source code.
using System;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0167_Error;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"Entering {args.Method.Name}." );
}
public class OrderService
{
public void PlaceOrder( string product, int quantity )
{
// The aspect is applied to a local function.
[Log]
string Describe() => $"{quantity} x {product}";
Console.WriteLine( $"Order placed: {Describe()}." );
}
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Chair", 4 );
}
}
error LA0167: LA0167_Error.cs(15,17): Cannot apply the aspect "Errors.LA0167_Error.LogAttribute" to "Errors.LA0167_Error.OrderService.PlaceOrder(System.String, System.Int32).Describe|0_0(Errors.LA0167_Error.OrderService.<>c__DisplayClass0_0@)": aspects cannot be applied to a declaration of kind "local function". Apply the aspect to a declaration of the source code instead. Code that selects the targets of an aspect, such as an IAspectProvider, can skip these declarations by checking MemberInfo.GetSemanticInfo().IsSelectable.
Resolution
- Turn the local function or the anonymous method into a method of the class, and apply the aspect to this method.
- Apply the aspect to the method that contains the local function, if the aspect is meant for it.
- In an aspect provider, skip the members whose GetSemanticInfo returns a SemanticInfo whose IsSelectable property is
false.
In the following example, Describe is a private method of OrderService, and the aspect logs its calls.
using System;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0167_Fixed;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"Entering {args.Method.Name}." );
}
public class OrderService
{
public void PlaceOrder( string product, int quantity )
{
Console.WriteLine( $"Order placed: {Describe( product, quantity )}." );
}
// The local function is now a method of the class, which can receive the aspect.
[Log]
private static string Describe( string product, int quantity ) => $"{quantity} x {product}";
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Chair", 4 );
}
}
Entering Describe.
Order placed: 4 x Chair.
See Also
Reference
SemanticInfo
GetSemanticInfo
IAspectProvider
Other Resources
Adding Aspects Programmatically Using IAspectProvider
Adding Aspects Declaratively Using Attributes