| 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