| Severity | Error |
| Reported by | PostSharp |
| Message | The parameter "<Parameter>" of the advice "<Advice>" is bound by [ImportMember] with IsRequired set to true, but the type "<TargetType>" has no accessible member named "<MemberNames>" that a parameter of type "<ParameterType>" can receive. A ref or out parameter requires a field that is not read-only or a property that returns a reference that is not read-only, a parameter passed by reference requires the exact type of the member, and IEventBinding and Event<T> require an event. |
Cause
An advice parameter annotated with ImportMemberAttribute with one or more member names receives the first member of these names that the parameter can receive. The candidates are the members of the target type and the accessible members of its base types, except indexers, constants and the fields generated by the compiler. A member of the name is not selected when:
- the parameter is passed as
reforout, and the member is a read-only field, or a property that does not return a reference that is not read-only; - the parameter is passed by reference, or is an ILocationBinding<T>, and the member does not have exactly its type;
- the parameter is passed by value, and the type of the member cannot be assigned to
<ParameterType>without a conversion other than boxing; - the parameter is a Property<TValue> and the member is not a property, or an IEventBinding or an Event<TDelegate> and the member is not an event.
When no member is selected, the parameter normally receives null, the default value, or a reference to a temporary variable. When IsRequired is true, PostSharp reports LA0281 on each target instead. <MemberNames> lists the names of the attribute, and <TargetType> is the type to which the aspect is applied, or the type that declares the target member. A delegate parameter whose names match no method of the target type also falls back to the fields and properties of the delegate type, and reports LA0281 when it finds none. When the advice uses a pointcut that skips the targets whose signature does not match, such as MatchPointcut, PostSharp skips the target instead of reporting the error.
In the following example, the [CountCalls] aspect increments a counter through a ref parameter, but CallCount is a property, which a ref parameter cannot reference.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0281_Error;
[PSerializable]
public sealed class CountCallsAttribute : MethodLevelAspect
{
[OnMethodEntryAdvice]
public static void OnEntry( [ImportMember( "CallCount", IsRequired = true )] ref int callCount )
{
callCount++;
}
}
public class Printer
{
public int CallCount { get; private set; }
// CallCount is a property, which the ref parameter of the aspect cannot reference.
[CountCalls]
public void Print( string text ) => Console.WriteLine( "Printing '{0}'.", text );
}
public static class Program
{
public static void Main()
{
Printer printer = new Printer();
printer.Print( "first" );
printer.Print( "second" );
Console.WriteLine( "CallCount = {0}", printer.CallCount );
}
}
error LA0281: LA0281_Error.cs(24,17): The parameter "callCount" of the advice "Errors.LA0281_Error.CountCallsAttribute.OnEntry(System.Int32@)" is bound by [ImportMember] with IsRequired set to true, but the type "Errors.LA0281_Error.Printer" has no accessible member named "CallCount" that a parameter of type "int32&" can receive. A ref or out parameter requires a field that is not read-only or a property that returns a reference that is not read-only, a parameter passed by reference requires the exact type of the member, and IEventBinding and Event<T> require an event.
Resolution
- Correct the name of the member in the attribute, or add a member of this name to the target type.
- To change the member through a
reforoutparameter, import a field that is not read-only, for instance the field behind the property, or pass the parameter by value to read a property. - Change the type of the advice parameter to the type of the member.
- Set IsRequired to
falseif the advice can work without the member.
In the following example, Printer stores the counter in a callCount field, which the aspect imports and increments.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0281_Fixed;
[PSerializable]
public sealed class CountCallsAttribute : MethodLevelAspect
{
[OnMethodEntryAdvice]
public static void OnEntry( [ImportMember( "callCount", IsRequired = true )] ref int callCount )
{
callCount++;
}
}
public class Printer
{
private int callCount = 0;
public int CallCount => this.callCount;
// The aspect imports the callCount field, which the ref parameter can reference.
[CountCalls]
public void Print( string text ) => Console.WriteLine( "Printing '{0}'.", text );
}
public static class Program
{
public static void Main()
{
Printer printer = new Printer();
printer.Print( "first" );
printer.Print( "second" );
Console.WriteLine( "CallCount = {0}", printer.CallCount );
}
}
Printing 'first'.
Printing 'second'.
CallCount = 2
See Also
Reference
ImportMemberAttribute
IsRequired
Other Resources