| Severity | Error |
| Reported by | PostSharp |
| Message | The parameter "<Parameter>" of the advice "<Advice>" is bound by [CurrentTask] with IsRequired set to true, but the advice can run before the method yields, when the task does not exist yet. Only an OnMethodResumeAdvice always runs after the method has yielded. |
Cause
A parameter annotated with CurrentTaskAttribute receives the task that the caller of the async method observes. This task exists only once the method has yielded, that is, once one of its await expressions has suspended it. Before, the parameter is null: in the entry advice, in the first yield advice, and in all the advices of an execution that completes without yielding.
When IsRequired is true, the parameter must never be null. Only an OnMethodResumeAdvice always runs after the method has yielded, so PostSharp reports LA0242 on the parameter when it is in any other advice. The error does not depend on the target methods.
In the following example, the entry advice of the [TrackTask] aspect requires the task.
using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0242_Error;
[PSerializable]
public class TrackTaskAttribute : MethodLevelAspect
{
[OnMethodEntryAdvice]
public static void OnEntry( [DeclarationName] string methodName,
// The entry advice runs before the method yields, when its task does not exist yet.
[CurrentTask( IsRequired = true )] Task task )
{
Console.WriteLine( $"{methodName} is running, its task is completed: {task.IsCompleted}." );
}
}
public class OrderService
{
[TrackTask]
public async Task SaveOrderAsync()
{
await Task.Delay( 10 );
Console.WriteLine( "Order saved." );
}
}
public static class Program
{
public static async Task Main()
{
await new OrderService().SaveOrderAsync();
}
}
error LA0242: LA0242_Error.cs(15,73): The parameter "task" of the advice "Errors.LA0242_Error.TrackTaskAttribute.OnEntry(System.String, System.Threading.Tasks.Task)" is bound by [CurrentTask] with IsRequired set to true, but the advice can run before the method yields, when the task does not exist yet. Only an OnMethodResumeAdvice always runs after the method has yielded.
Resolution
- Move the parameter to an OnMethodResumeAdvice. If the entry advice of the same aspect has an AwaiterAttribute parameter, the resume advice can also run before the method yields, and PostSharp reports LA0244.
- Or set IsRequired to
false, and handle anulltask in the advice.
In the following example, the parameter is in the resume advice.
using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0242_Fixed;
[PSerializable]
public class TrackTaskAttribute : MethodLevelAspect
{
[OnMethodResumeAdvice]
public static void OnResume( [DeclarationName] string methodName,
// The resume advice runs after the method has yielded, when its task exists.
[CurrentTask( IsRequired = true )] Task task )
{
Console.WriteLine( $"{methodName} is running, its task is completed: {task.IsCompleted}." );
}
}
public class OrderService
{
[TrackTask]
public async Task SaveOrderAsync()
{
await Task.Delay( 10 );
Console.WriteLine( "Order saved." );
}
}
public static class Program
{
public static async Task Main()
{
await new OrderService().SaveOrderAsync();
}
}
SaveOrderAsync is running, its task is completed: False.
Order saved.
See Also
Reference
CurrentTaskAttribute
OnMethodResumeAdvice
Other Resources
Advice Parameters
Semantic Advising of Iterator and Async Methods