| Severity | Error |
| Reported by | PostSharp |
| Message | Error while evaluating the MethodPointcut "<PointcutMethod>" on "<AspectTarget>": cannot select the <ElementKind> "<Element>" because it does not belong to type "<TargetType>", and an instance-scoped aspect can only add advices to the members of its own target type. |
Cause
An advice can select its targets with MethodPointcut, which names a method of the aspect that returns the declarations to enhance. An instance-scoped aspect, such as an InstanceLevelAspect, has one instance per instance of its target type, stored in a field of that type. Its advices can only run in the members of that type, which can read the field: a member of another type, even of a base class, cannot reach the instance of the aspect.
PostSharp reports LA0110 for each element that the pointcut method returns when the element is declared in another type than <TargetType>, the type that the aspect is applied to. The error is reported on the pointcut method, and the element is skipped. <ElementKind> is the kind of metadata element, such as MethodDef for a method.
Static-scoped aspects, such as TypeLevelAspect, do not have this restriction.
In the following example, the [Trace] aspect, applied to OrderService, selects the methods of the ServiceBase base class.
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0110_Error;
[PSerializable]
public class TraceAttribute : InstanceLevelAspect
{
// The instance-scoped aspect selects the methods of the base class, which is another type.
private IEnumerable<MethodInfo> SelectMethods( Type type )
=> type.BaseType!.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly );
[OnMethodEntryAdvice, MethodPointcut( nameof(SelectMethods) )]
public void OnEntry( MethodExecutionArgs args )
{
Console.WriteLine( $"Entering {args.Method.DeclaringType!.Name}.{args.Method.Name}." );
}
}
public class ServiceBase
{
public void Start() => Console.WriteLine( "Service started." );
}
[Trace]
public class OrderService : ServiceBase
{
public void PlaceOrder() => Console.WriteLine( "Order placed." );
}
public static class Program
{
public static void Main()
{
var service = new OrderService();
service.Start();
service.PlaceOrder();
}
}
error LA0110: LA0110_Error.cs(14,37): Error while evaluating the MethodPointcut "Errors.LA0110_Error.TraceAttribute.SelectMethods(System.Type)" on "Errors.LA0110_Error.OrderService": cannot select the MethodDef "Errors.LA0110_Error.ServiceBase.Start" because it does not belong to type "Errors.LA0110_Error.OrderService", and an instance-scoped aspect can only add advices to the members of its own target type.
Resolution
- Select only the members that the target type declares, with
BindingFlags.DeclaredOnly, and apply the aspect to the other types whose members you want to enhance. - If the aspect does not need an instance per instance of the target type, derive it from TypeLevelAspect instead.
In the following example, the aspect is applied to both classes, and each instance of the aspect selects the methods of its own target type.
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0110_Fixed;
[PSerializable]
public class TraceAttribute : InstanceLevelAspect
{
// The aspect selects only the methods of its own target type.
private IEnumerable<MethodInfo> SelectMethods( Type type )
=> type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly );
[OnMethodEntryAdvice, MethodPointcut( nameof(SelectMethods) )]
public void OnEntry( MethodExecutionArgs args )
{
Console.WriteLine( $"Entering {args.Method.DeclaringType!.Name}.{args.Method.Name}." );
}
}
// The aspect is applied to the base class to trace its methods.
[Trace]
public class ServiceBase
{
public void Start() => Console.WriteLine( "Service started." );
}
[Trace]
public class OrderService : ServiceBase
{
public void PlaceOrder() => Console.WriteLine( "Order placed." );
}
public static class Program
{
public static void Main()
{
var service = new OrderService();
service.Start();
service.PlaceOrder();
}
}
Entering ServiceBase.Start.
Service started.
Entering OrderService.PlaceOrder.
Order placed.
See Also
Reference
MethodPointcut
InstanceLevelAspect
TypeLevelAspect
Other Resources
Selecting Members with Pointcuts
Understanding Aspect Lifetime and Scope