Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/fundamentals/code-analysis/quality-rules/ca2012.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ helpviewer_keywords:
- "CA2012"
author: stephentoub
ms.author: stoub
dev_langs:
- CSharp
---
# CA2012: Use ValueTasks correctly

Expand Down Expand Up @@ -37,6 +39,10 @@ In general, ValueTasks should be directly awaited rather than discarded or store

For `ValueTask` objects returned from arbitrary member calls, the caller needs to assume that the `ValueTask` must be consumed (for example, awaited) once and only once. However, if the developer also controls the member being invoked and has complete knowledge of its implementation, the developer may know it's safe to suppress the warning, for example, if the return `ValueTask` always wraps a <xref:System.Threading.Tasks.Task> object.

## Example

:::code language="csharp" source="snippets/csharp/all-rules/ca2012.cs" id="snippet1":::

## Suppress a warning

If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Threading.Tasks;

namespace ca2012
{
//<snippet1>
public class NumberValueTask
{
public async ValueTask<int> GetNumberAsync()
{
await Task.Delay(100);
return 123;
}

public async Task UseValueTaskIncorrectlyAsync()
{
// This code violates the rule,
// because ValueTask is awaited multiple times
ValueTask<int> numberValueTask = GetNumberAsync();

int first = await numberValueTask;
int second = await numberValueTask; // <- illegal reuse

// ...
}

// This code satisfies the rule.
public async Task UseValueTaskCorrectlyAsync()
{
int first = await GetNumberAsync();
int second = await GetNumberAsync();

// ..
}

public async Task UseValueTaskAsTaskAsync()
{
ValueTask<int> numberValueTask = GetNumberAsync();

Task<int> numberTask = numberValueTask.AsTask();

int first = await numberTask;
int second = await numberTask;

// ...
}
}
//</snippet1>
}