56 lines
2.9 KiB
Plaintext
56 lines
2.9 KiB
Plaintext
``++ValueTask<TResult>++`` was introduced in .NET Core 2.0 https://devblogs.microsoft.com/dotnet/understanding-the-whys-whats-and-whens-of-valuetask/[to optimize memory allocation] when functions return their results synchronously.
|
|
|
|
|
|
``++ValueTask++`` and ``++ValueTask<TResult>++`` should *never* be used in the following ways as it could result in a race condition:
|
|
|
|
* Calling ``++await++`` multiple times on a ``++ValueTask / ValueTask<TResult>++``*. The wrapped object may have been reused by another operation. This differs from ``++Task / Task<TResult>++``, on which you can await multiple times and always get the same result.
|
|
* Calling ``++await++`` concurrently on a ``++ValueTask / ValueTask<TResult>++``*. The underlying object is not thread safe. What's more, it has the same effect as awaiting multiple times a ``++ValueTask / ValueTask<TResult>++``. This again differs from ``++Task / Task<TResult>++``, which support concurrent ``++await++``.
|
|
* Using ``++.Result++`` or ``++.GetAwaiter().GetResult()++`` without checking if the operation completed*. ``++IValueTaskSource / IValueTaskSource<TResult>++`` implementations are not required to block until the operation completes. On the other hand, ``++Task / Task<TResult>++`` blocks the call until the task completes.
|
|
|
|
It is recommended to use ``++ValueTask / ValueTask<TResult>++`` either by calling "await" on the function returning it, optionally calling ``++ConfigureAwait(false)++`` on it, or by calling ``++.AsTask()++`` on it.
|
|
|
|
|
|
This rule raises an issue when the following operations are performed on a ``++ValueTask / ValueTask<TResult>++`` instance:
|
|
|
|
* Awaiting the instance multiple times.
|
|
* Calling ``++AsTask++`` multiple times.
|
|
* Using ``++.Result++`` or ``++.GetAwaiter().GetResult()++`` multiple times
|
|
* Using ``++.Result++`` or ``++.GetAwaiter().GetResult()++`` when the operation has not yet completed
|
|
* Using more than one of these ways to consume the instance.
|
|
|
|
|
|
== Noncompliant Code Example
|
|
|
|
[source,text]
|
|
----
|
|
ValueTask<int> vt = SomeValueTaskReturningMethodAsync();
|
|
int result = await vt;
|
|
int result2 = await vt; // Noncompliant, variable is awaited multiple times
|
|
|
|
int value = SomeValueTaskReturningMethodAsync().GetAwaiter().GetResult(); // Noncompliant, uses GetAwaiter().GetResult() when it's not known to be done
|
|
----
|
|
|
|
|
|
== Compliant Solution
|
|
|
|
[source,text]
|
|
----
|
|
int result = await SomeValueTaskReturningMethodAsync();
|
|
|
|
int result = await SomeValueTaskReturningMethodAsync().ConfigureAwait(false);
|
|
|
|
Task<int> t = SomeValueTaskReturningMethodAsync().AsTask();
|
|
----
|
|
|
|
|
|
== Exceptions
|
|
|
|
This rule does not raise any issue when a ``++ValueTask / ValueTask<TResult>++`` is awaited multiple time in a loop.
|
|
|
|
|
|
== See
|
|
|
|
* https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1[ValueTask<TResult> official documentation]
|
|
* https://blogs.msdn.microsoft.com/dotnet/2018/11/07/understanding-the-whys-whats-and-whens-of-valuetask/[Understanding the Whys, Whats, and Whens of ValueTask]
|
|
|