| Severity | Error |
| Reported by | PostSharp |
| Message | The parameter "<Parameter>" of the advice "<Advice>" is bound by <Binding>, but "<TargetMethod>" is not transformed as an async method, so it has no awaited task. |
Cause
In an OnMethodYieldAdvice, a parameter annotated with AwaitedTaskAttribute receives the task that the async method awaits, and a parameter annotated with AwaitedMethodAttribute receives the method that returned it. PostSharp records these values at each await expression when it transforms the state machine of an async method.
An iterator also has a state machine, and the yield advice runs at its yield return statements, but an iterator awaits nothing. When the yield advice is applied to a method that PostSharp does not transform as an async method, such as an iterator, there is no awaited task or method to pass, and PostSharp reports LA0238 on the target method. <Binding> is [AwaitedTask] or [AwaitedMethod]. The error is reported when PostSharp generates the code of the advice, so a MatchPointcut does not skip such a target.
In the following example, the [TraceAwaits] aspect is applied to an async method and to an iterator.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0238_Error;
[PSerializable]
public class TraceAwaitsAttribute : MethodLevelAspect
{
[OnMethodYieldAdvice]
public static void OnYield( [DeclarationName] string methodName, [AwaitedTask] Task? awaitedTask )
{
Console.WriteLine( $"{methodName} awaits a task: {awaitedTask != null}." );
}
}
public class OrderService
{
[TraceAwaits]
public async Task<int> CountOrdersAsync()
{
await Task.Delay( 10 );
return 3;
}
// An iterator yields values but awaits no task.
[TraceAwaits]
public IEnumerable<string> GetOrderNumbers()
{
yield return "A-100";
yield return "A-101";
}
}
public static class Program
{
public static async Task Main()
{
OrderService service = new OrderService();
int count = await service.CountOrdersAsync();
Console.WriteLine( $"{count} orders." );
foreach ( string number in service.GetOrderNumbers() )
{
Console.WriteLine( number );
}
}
}
error LA0238: LA0238_Error.cs(32,32): The parameter "awaitedTask" of the advice "Errors.LA0238_Error.TraceAwaitsAttribute.OnYield(System.String, System.Threading.Tasks.Task)" is bound by [AwaitedTask], but "Errors.LA0238_Error.OrderService.GetOrderNumbers" is not transformed as an async method, so it has no awaited task.
Resolution
- Apply the aspect only to async methods.
- Or, when the aspect must also handle iterators, move the
[AwaitedTask]and[AwaitedMethod]parameters to an aspect that is applied only to async methods.
In the following example, the aspect is removed from the iterator.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0238_Fixed;
[PSerializable]
public class TraceAwaitsAttribute : MethodLevelAspect
{
[OnMethodYieldAdvice]
public static void OnYield( [DeclarationName] string methodName, [AwaitedTask] Task? awaitedTask )
{
Console.WriteLine( $"{methodName} awaits a task: {awaitedTask != null}." );
}
}
public class OrderService
{
[TraceAwaits]
public async Task<int> CountOrdersAsync()
{
await Task.Delay( 10 );
return 3;
}
// The aspect is applied only to async methods.
public IEnumerable<string> GetOrderNumbers()
{
yield return "A-100";
yield return "A-101";
}
}
public static class Program
{
public static async Task Main()
{
OrderService service = new OrderService();
int count = await service.CountOrdersAsync();
Console.WriteLine( $"{count} orders." );
foreach ( string number in service.GetOrderNumbers() )
{
Console.WriteLine( number );
}
}
}
CountOrdersAsync awaits a task: True.
3 orders.
A-100
A-101
See Also
Reference
AwaitedTaskAttribute
AwaitedMethodAttribute
OnMethodYieldAdvice
Other Resources
Advice Parameters
Semantic Advising of Iterator and Async Methods