Open sandboxFocusImprove this doc

LA0263: No Method Converts to the Delegate Type of a Required Imported Member

Severity Error
Reported by PostSharp
Message The parameter "<Parameter>" of the advice "<Advice>" is bound by [ImportMember] with IsRequired set to true, but no method "<Method>" of the type "<TargetType>" converts to the delegate type "<DelegateType>". The first parameter of the delegate receives the object of an instance method, by reference for a struct (in for any method, ref for a method that is not readonly). The other parameters must convert to the parameters of the method, and the return type of the method to the return type of the delegate, by an identity or reference conversion.

Cause

An advice parameter of a delegate type, marked with ImportMemberAttribute and a method name, receives an open delegate of a method of the target type. PostSharp selects the method as C# converts a method group to a delegate type:

  • For an instance method, the first parameter of the delegate receives the object. For a struct, it must be in, or ref for a method that is not readonly.
  • The other parameters of the delegate must convert to the parameters of the method, with the same ref, out or in modifier.
  • The return type of the method must convert to the return type of the delegate.

Only identity and reference conversions are allowed. A numeric conversion, such as int to long, or a boxing conversion, such as int to object, does not make a method convert.

When no method of this name converts to the delegate type and IsRequired is true, PostSharp reports LA0263 on the target method. PostSharp also reports it when the advice is generic and the method selected for the delegate requires type arguments that contradict those that the other parameters of the advice infer.

In the following example, the advice imports CountPendingOrders as a Func<OrderService, long>, but the method returns an int.

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

namespace Errors.LA0263_Error;

[PSerializable]
public class LogPendingOrdersAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice]
    public static void OnEntry( [This] OrderService service,
                                // CountPendingOrders returns an int, which does not convert to the long that the delegate returns.
                                [ImportMember( "CountPendingOrders", IsRequired = true )] Func<OrderService, long> countPendingOrders )
    {
        Console.WriteLine( $"Pending orders: {countPendingOrders( service )}" );
    }
}

public class OrderService
{
    private int pendingOrders;

    public int CountPendingOrders() => this.pendingOrders;

    [LogPendingOrders]
    public void PlaceOrder( string product )
    {
        this.pendingOrders++;
        Console.WriteLine( $"Placed an order for {product}." );
    }
}

public static class Program
{
    public static void Main()
    {
        var service = new OrderService();
        service.PlaceOrder( "Book" );
        service.PlaceOrder( "Pen" );
    }
}
error LA0263: LA0263_Error.cs(27,17): The parameter "countPendingOrders" of the advice "Errors.LA0263_Error.LogPendingOrdersAttribute.OnEntry(Errors.LA0263_Error.OrderService, System.Func<Errors.LA0263_Error.OrderService,System.Int64>)" is bound by [ImportMember] with IsRequired set to true, but no method "CountPendingOrders" of the type "Errors.LA0263_Error.OrderService" converts to the delegate type "System.Func`2<Errors.LA0263_Error.OrderService,int64>". The first parameter of the delegate receives the object of an instance method, by reference for a struct (in for any method, ref for a method that is not readonly). The other parameters must convert to the parameters of the method, and the return type of the method to the return type of the delegate, by an identity or reference conversion.

Resolution

  • Change the delegate type so that its parameter types and its return type match those of the method.
  • If the parameter is optional, set IsRequired to false, its default value: the parameter then receives null when no method converts.
  • In a type-level aspect whose target types do not all define a suitable method, select the targets with MatchPointcut, which skips the targets that the advice does not fit instead of reporting an error.

In the following example, the delegate type returns an int, as the method does.

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

namespace Errors.LA0263_Fixed;

[PSerializable]
public class LogPendingOrdersAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice]
    public static void OnEntry( [This] OrderService service,
                                // The delegate returns an int, as CountPendingOrders does.
                                [ImportMember( "CountPendingOrders", IsRequired = true )] Func<OrderService, int> countPendingOrders )
    {
        Console.WriteLine( $"Pending orders: {countPendingOrders( service )}" );
    }
}

public class OrderService
{
    private int pendingOrders;

    public int CountPendingOrders() => this.pendingOrders;

    [LogPendingOrders]
    public void PlaceOrder( string product )
    {
        this.pendingOrders++;
        Console.WriteLine( $"Placed an order for {product}." );
    }
}

public static class Program
{
    public static void Main()
    {
        var service = new OrderService();
        service.PlaceOrder( "Book" );
        service.PlaceOrder( "Pen" );
    }
}
Pending orders: 0
Placed an order for Book.
Pending orders: 1
Placed an order for Pen.

See Also

Reference

ImportMemberAttribute
MatchPointcut

Other Resources

Advice Parameters