| Severity | Error |
| Reported by | PostSharp |
| Message | Incorrect type of the [Awaiter] parameter in "<Advice>". The parameter must be passed by reference and implement ICriticalNotifyCompletion or INotifyCompletion. |
Cause
An entry or resume advice of an async method can make the method await an awaiter of the aspect before it continues: the advice assigns the awaiter to a parameter annotated with AwaiterAttribute and sets its [FlowBehavior] parameter to FlowBehavior.Yield. The advice gives the awaiter to the method through the parameter, so the parameter must be passed by reference, as out or ref, and its type must be an awaiter, which implements INotifyCompletion or ICriticalNotifyCompletion. PostSharp reports LA0152 when the parameter is passed by value or when its type implements neither interface.
In the following example, the [SwitchToThreadPool] aspect receives the awaiter by value.
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0152_Error;
[PSerializable]
public class SwitchToThreadPoolAttribute : MethodLevelAspect
{
[OnMethodEntryAdvice]
public void OnEntry( [FlowBehavior] out FlowBehavior flowBehavior,
// The awaiter is passed by value, so the advice cannot give it to the method.
[Awaiter] YieldAwaitable.YieldAwaiter awaiter )
{
Console.WriteLine( "Switching to the thread pool." );
flowBehavior = FlowBehavior.Yield;
}
}
public class ReportService
{
[SwitchToThreadPool]
public async Task GenerateAsync()
{
Console.WriteLine( "Generating the report." );
await Task.CompletedTask;
}
}
public static class Program
{
public static void Main()
{
new ReportService().GenerateAsync().Wait();
}
}
error LA0152: LA0152_Error.cs(16,64): Incorrect type of the [Awaiter] parameter in "Errors.LA0152_Error.SwitchToThreadPoolAttribute.OnEntry(PostSharp.Aspects.FlowBehavior@, System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter)". The parameter must be passed by reference and implement ICriticalNotifyCompletion or INotifyCompletion.
Resolution
- Pass the
[Awaiter]parameter asoutorref, and assign the awaiter in the advice. - Give the parameter the type of an awaiter, such as the one that
Task.Yield().GetAwaiter()returns, or a type of your own that implements INotifyCompletion. A task is not an awaiter: use the awaiter that itsGetAwaitermethod returns.
In the following example, the advice assigns the awaiter to an out parameter, and the method continues on the thread pool.
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0152_Fixed;
[PSerializable]
public class SwitchToThreadPoolAttribute : MethodLevelAspect
{
[OnMethodEntryAdvice]
public void OnEntry( [FlowBehavior] out FlowBehavior flowBehavior,
// The awaiter is an out parameter, which the advice assigns.
[Awaiter] out YieldAwaitable.YieldAwaiter awaiter )
{
Console.WriteLine( "Switching to the thread pool." );
awaiter = Task.Yield().GetAwaiter();
flowBehavior = FlowBehavior.Yield;
}
}
public class ReportService
{
[SwitchToThreadPool]
public async Task GenerateAsync()
{
Console.WriteLine( "Generating the report." );
await Task.CompletedTask;
}
}
public static class Program
{
public static void Main()
{
new ReportService().GenerateAsync().Wait();
}
}
Switching to the thread pool.
Generating the report.
See Also
Reference
AwaiterAttribute
FlowBehaviorAttribute
FlowBehavior
Other Resources