| Severity | Error |
| Reported by | PostSharp |
| Message | The parameter "<Parameter>" of the advice "<Advice>" must be passed by reference (out or ref) because it is bound by <Binding>. |
Cause
Each binding attribute accepts some parameter modes in each kind of advice. A parameter annotated with ReturnValueAttribute must be out or ref in the following advices, because the return value does not exist yet when they run, and the advice can only set it:
- OnMethodEntryAdvice and OnMethodExceptionAdvice, where the parameter sets the value that the method returns when the advice sets the flow behavior to FlowBehavior.Return.
- OnMethodInvokeAdvice, where the advice assigns the value that the intercepted method returns.
When the parameter is passed by value or as in, PostSharp reports LA0212 on the parameter. <Binding> is the binding attribute as you write it, [ReturnValue]. For the other modes and advices, see Reading and setting the return value.
In the following example, the entry advice of the [CacheStock] aspect returns a cached value through a [ReturnValue] parameter passed by value. PostSharp reports the message without a file and a line here, because the advice also has an out parameter.
using System;
using System.Collections.Generic;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0212_Error;
[PSerializable]
public class CacheStockAttribute : MethodLevelAspect
{
private static readonly Dictionary<int, int> _cache = new();
[OnMethodEntryAdvice]
// An entry advice sets the return value, so the stock parameter must be out or ref.
public void OnEntry( [Argument( 0 )] int productId, [ReturnValue] int stock, [FlowBehavior] out FlowBehavior flowBehavior )
{
if ( _cache.TryGetValue( productId, out int cachedStock ) )
{
stock = cachedStock;
flowBehavior = FlowBehavior.Return;
}
else
{
stock = 0;
flowBehavior = FlowBehavior.Default;
}
}
[OnMethodSuccessAdvice]
public void OnSuccess( [Argument( 0 )] int productId, [ReturnValue] int stock )
{
_cache[productId] = stock;
}
}
public class InventoryService
{
[CacheStock]
public int GetStock( int productId )
{
Console.WriteLine( $"Counting the stock of product {productId}." );
return 12;
}
}
public static class Program
{
public static void Main()
{
InventoryService service = new();
Console.WriteLine( service.GetStock( 1 ) );
Console.WriteLine( service.GetStock( 1 ) );
}
}
error LA0212: LA0212_Error.cs(16,75): The parameter "stock" of the advice "Errors.LA0212_Error.CacheStockAttribute.OnEntry(System.Int32, System.Int32, PostSharp.Aspects.FlowBehavior@)" must be passed by reference (out or ref) because it is bound by [ReturnValue].
Resolution
Declare the parameter as out, or as ref when the advice also reads the value that another advice set. To read the return value of the method, use the [ReturnValue] parameter of an OnMethodSuccessAdvice or an OnMethodExitAdvice instead.
In the following example, the stock parameter of the entry advice is out, so the second call returns the cached value without executing the method.
using System;
using System.Collections.Generic;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0212_Fixed;
[PSerializable]
public class CacheStockAttribute : MethodLevelAspect
{
private static readonly Dictionary<int, int> _cache = new();
[OnMethodEntryAdvice]
// The out parameter sets the value that the method returns with FlowBehavior.Return.
public void OnEntry( [Argument( 0 )] int productId, [ReturnValue] out int stock, [FlowBehavior] out FlowBehavior flowBehavior )
{
if ( _cache.TryGetValue( productId, out int cachedStock ) )
{
stock = cachedStock;
flowBehavior = FlowBehavior.Return;
}
else
{
stock = 0;
flowBehavior = FlowBehavior.Default;
}
}
[OnMethodSuccessAdvice]
public void OnSuccess( [Argument( 0 )] int productId, [ReturnValue] int stock )
{
_cache[productId] = stock;
}
}
public class InventoryService
{
[CacheStock]
public int GetStock( int productId )
{
Console.WriteLine( $"Counting the stock of product {productId}." );
return 12;
}
}
public static class Program
{
public static void Main()
{
InventoryService service = new();
Console.WriteLine( service.GetStock( 1 ) );
Console.WriteLine( service.GetStock( 1 ) );
}
}
Counting the stock of product 1.
12
12
See Also
Reference
ReturnValueAttribute
FlowBehaviorAttribute
OnMethodEntryAdvice
Other Resources