Open sandboxFocusImprove this doc

LA0280: Unsupported Type of an ImportMember Parameter

Severity Error
Reported by PostSharp
Message The parameter "<Parameter>" of the advice "<Advice>" is bound by [ImportMember], but its type "<ParameterType>" is not supported. A parameter bound by [ImportMember] receives a field or a property of the target type, as a value of the type of the member or as ILocationBinding<T> or ILocationBinding, a method, as a delegate whose first parameter receives the object or as IMethodBinding, an event as IEventBinding, or, in an instance advice of an instance-scoped aspect, a property as Property<T> or an event as Event<T>. Property<T, TIndex> is not supported.

Cause

The type of an advice parameter annotated with ImportMemberAttribute selects what the parameter receives: the value of a field or a property, a location binding, a delegate or an IMethodBinding of a method, an IEventBinding of an event, or a Property<TValue> or an Event<TDelegate>. PostSharp reports LA0280 for a parameter of type Property<TValue, TIndex>, which would import an indexer. Indexers are not candidates of an import.

In the following example, the instance-scoped [LogPrice] aspect imports the indexer of PriceList as a Property<TValue, TIndex> to read a price.

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

namespace Errors.LA0280_Error;

[PSerializable]
public class LogPriceAttribute : MethodLevelAspect, IInstanceScopedAspect
{
    public object CreateInstance( AdviceArgs adviceArgs ) => new LogPriceAttribute();

    public void RuntimeInitializeInstance()
    {
    }

    // Property<T, TIndex> is not supported on an advice parameter.
    [OnMethodEntryAdvice]
    public void OnEntry( [Argument( 0 )] string product, [ImportMember( "Item", IsRequired = true )] Property<decimal, string> price )
    {
        Console.WriteLine( $"Price of {product}: {price.Get( product )}." );
    }
}

public class PriceList
{
    private readonly Dictionary<string, decimal> prices = new() { ["Coffee"] = 3.5m };

    public decimal this[ string product ] => this.prices[product];

    [LogPrice]
    public void Order( string product )
    {
        Console.WriteLine( $"Ordered {product}." );
    }
}

public static class Program
{
    public static void Main()
    {
        new PriceList().Order( "Coffee" );
    }
}
error LA0280: LA0280_Error.cs(20,128): The parameter "price" of the advice "Errors.LA0280_Error.LogPriceAttribute.OnEntry(System.String, PostSharp.Aspects.Advices.Property<System.Decimal,System.String>)" is bound by [ImportMember], but its type "PostSharp.Aspects.Advices.Property`2<System.Decimal,string>" is not supported. A parameter bound by [ImportMember] receives a field or a property of the target type, as a value of the type of the member or as ILocationBinding<T> or ILocationBinding, a method, as a delegate whose first parameter receives the object or as IMethodBinding, an event as IEventBinding, or, in an instance advice of an instance-scoped aspect, a property as Property<T> or an event as Event<T>. Property<T, TIndex> is not supported.

Resolution

To access an indexer, add a method that wraps it to the target type, and import this method as a delegate or as an IMethodBinding.

In the following example, PriceList wraps its indexer in a GetPrice method, which the aspect imports as an open delegate. The aspect no longer needs to be instance-scoped.

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

namespace Errors.LA0280_Fixed;

[PSerializable]
public class LogPriceAttribute : MethodLevelAspect
{
    // The open delegate calls GetPrice, which wraps the indexer, on the instance received by [This].
    [OnMethodEntryAdvice]
    public void OnEntry<T>( [This] T instance, [Argument( 0 )] string product,
                            [ImportMember( "GetPrice", IsRequired = true )] Func<T, string, decimal> getPrice )
    {
        Console.WriteLine( $"Price of {product}: {getPrice( instance, product )}." );
    }
}

public class PriceList
{
    private readonly Dictionary<string, decimal> prices = new() { ["Coffee"] = 3.5m };

    public decimal this[ string product ] => this.prices[product];

    public decimal GetPrice( string product ) => this[product];

    [LogPrice]
    public void Order( string product )
    {
        Console.WriteLine( $"Ordered {product}." );
    }
}

public static class Program
{
    public static void Main()
    {
        new PriceList().Order( "Coffee" );
    }
}
Price of Coffee: 3.5.
Ordered Coffee.

See Also

Reference

ImportMemberAttribute
Property<TValue, TIndex>

Other Resources

Advice Parameters