Open sandboxFocusImprove this doc

LA0217: Advice Parameter Type Incompatible with the Target

Severity Error
Reported by PostSharp
Message The parameter "<Parameter>" of the advice "<Advice>" is of type "<ParameterType>", which is not compatible with the value of type "<ValueType>" bound on "<Target>".

Cause

Some bindings give a value whose type depends on the target of the advice: ArgumentAttribute gives an argument, ReturnValueAttribute the return value, ThisAttribute the instance, LocationValueAttribute the value of a field or property, and DeclarationAttribute a reflection object that is a method or a constructor. PostSharp checks the type of the parameter for each target, and reports LA0217 on the target when the parameter cannot receive the value:

  • A parameter passed by value must generally be of the type of the value, or of a base type when the value is of a reference type. A parameter of a reference type, such as object, also receives a boxed copy of a value of a value type.
  • A parameter passed as in, ref or out must be exactly of the type of the value.
  • A [Declaration] parameter of type MethodInfo cannot receive a constructor, and a parameter of type ConstructorInfo cannot receive a method.

The message is reported on <Target>, the declaration to which the advice is applied. The same advice can fit some targets and not others.

In the following example, the advice binds the first argument to a string parameter, which fits PlaceOrder but not CancelOrders, whose first argument is an int.

using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.LA0217_Error;

[PSerializable]
public class LogCustomerAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice]
    public static void OnEntry( [DeclarationName] string methodName, [Argument( 0 )] string customerId )
    {
        Console.WriteLine( $"{methodName}: customer {customerId}." );
    }
}

public class OrderService
{
    [LogCustomer]
    public void PlaceOrder( string customerId ) => Console.WriteLine( "Order placed." );

    // The first argument of this method is an int, which a string parameter cannot receive.
    [LogCustomer]
    public void CancelOrders( int customerId ) => Console.WriteLine( "Orders canceled." );
}

public static class Program
{
    public static void Main()
    {
        OrderService service = new OrderService();
        service.PlaceOrder( "C-042" );
        service.CancelOrders( 42 );
    }
}
error LA0217: LA0217_Error.cs(25,17): The parameter "customerId" of the advice "Errors.LA0217_Error.LogCustomerAttribute.OnEntry(System.String, System.String)" is of type "string", which is not compatible with the value of type "int32" bound on "Errors.LA0217_Error.OrderService.CancelOrders(System.Int32)".

Resolution

Choose one of the following solutions:

  • Give the parameter a type that receives the value on every target: a common base type, or object, which receives a boxed copy of a value type.
  • Make the advice generic, so that PostSharp infers the type of the parameter for each target without boxing. See Generic advice methods.
  • Do not apply the aspect to the targets that do not fit. In a type-level aspect, the MatchPointcut pointcut skips these targets instead of reporting an error.

In the following example, the parameter is of type object, so the advice receives the argument of both methods.

using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.LA0217_Fixed;

[PSerializable]
public class LogCustomerAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice]
    // A parameter of type object receives an argument of any type, boxed when it is a value type.
    public static void OnEntry( [DeclarationName] string methodName, [Argument( 0 )] object customerId )
    {
        Console.WriteLine( $"{methodName}: customer {customerId}." );
    }
}

public class OrderService
{
    [LogCustomer]
    public void PlaceOrder( string customerId ) => Console.WriteLine( "Order placed." );

    [LogCustomer]
    public void CancelOrders( int customerId ) => Console.WriteLine( "Orders canceled." );
}

public static class Program
{
    public static void Main()
    {
        OrderService service = new OrderService();
        service.PlaceOrder( "C-042" );
        service.CancelOrders( 42 );
    }
}
PlaceOrder: customer C-042.
Order placed.
CancelOrders: customer 42.
Orders canceled.

See Also

Reference

ArgumentAttribute
MatchPointcut

Other Resources

Advice Parameters