| Severity | Error |
| Reported by | PostSharp |
| Message | The parameter "<Parameter>" of the advice "<Advice>" is bound by reference to the argument at index <Index> of "<Target>", but the address of this argument cannot be loaded in this advice. This happens when the method has more than eight parameters and PostSharp stores its arguments in an array. |
Cause
A parameter of an advice annotated with ArgumentAttribute and passed as ref, out or in receives the address of an argument of the target method, so that the advice can read or replace the argument. PostSharp loads this address when it generates the code of the advice. When it cannot, it reports LA0222 on the target method. <Index> is the zero-based index of the argument.
The address is not available when PostSharp keeps the arguments in an Arguments object instead of the parameters or the fields of a state machine, and the method has more than eight parameters: the arguments are then stored as objects in an array, which has no field of the type of the argument. This happens when a method boundary advice is applied to a method that returns a task but is not async: PostSharp generates the state machine of this method, and stores the arguments in an Arguments object.
In the following example, the [NormalizeEmail] aspect replaces the email argument of RegisterAsync, which returns a task without being async, and has nine parameters.
using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0222_Error;
[PSerializable]
public class NormalizeEmailAttribute : MethodLevelAspect
{
// The advice replaces the email argument with its trimmed, lowercase form.
[OnMethodEntryAdvice]
public static void OnEntry( [Argument( "email" )] ref string email )
{
email = email.Trim().ToLowerInvariant();
}
}
public class CustomerService
{
// The method is not async, so PostSharp generates its state machine, which stores the nine arguments in an array.
[NormalizeEmail]
public Task<string> RegisterAsync( string firstName, string lastName, string email, string phone, string street, string city,
string postalCode, string country, string language )
=> Task.FromResult( $"{firstName} {lastName} <{email}>, {city}, {country}" );
}
public static class Program
{
public static async Task Main()
{
string customer = await new CustomerService().RegisterAsync( "Alice", "Martin", " Alice.Martin@Example.COM ", "+32 2 555 0100",
"Rue Haute 12", "Brussels", "1000", "Belgium", "fr" );
Console.WriteLine( customer );
}
}
error LA0222: LA0222_Error.cs(24,25): The parameter "email" of the advice "Errors.LA0222_Error.NormalizeEmailAttribute.OnEntry(System.String@)" is bound by reference to the argument at index 2 of "Errors.LA0222_Error.CustomerService.RegisterAsync(System.String, System.String, System.String, System.String, System.String, System.String, System.String, System.String, System.String)", but the address of this argument cannot be loaded in this advice. This happens when the method has more than eight parameters and PostSharp stores its arguments in an array.
Resolution
- Make the method
async. The advice then runs in the state machine that the C# compiler generates, which stores each argument in a field of its own type. - Reduce the number of parameters of the method to eight or fewer, for example by grouping them into a class or a record.
- Bind the argument by value, when the advice only reads it.
In the following example, RegisterAsync is async.
using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0222_Fixed;
[PSerializable]
public class NormalizeEmailAttribute : MethodLevelAspect
{
// The advice replaces the email argument with its trimmed, lowercase form.
[OnMethodEntryAdvice]
public static void OnEntry( [Argument( "email" )] ref string email )
{
email = email.Trim().ToLowerInvariant();
}
}
public class CustomerService
{
// The method is async, so the advice runs in the state machine of the compiler, which stores each argument in a field.
[NormalizeEmail]
public async Task<string> RegisterAsync( string firstName, string lastName, string email, string phone, string street, string city,
string postalCode, string country, string language )
{
await Task.Yield();
return $"{firstName} {lastName} <{email}>, {city}, {country}";
}
}
public static class Program
{
public static async Task Main()
{
string customer = await new CustomerService().RegisterAsync( "Alice", "Martin", " Alice.Martin@Example.COM ", "+32 2 555 0100",
"Rue Haute 12", "Brussels", "1000", "Belgium", "fr" );
Console.WriteLine( customer );
}
}
Alice Martin <alice.martin@example.com>, Brussels, Belgium
See Also
Reference
Other Resources
Advice Parameters
Semantic Advising of Iterator and Async Methods