-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
When working with ValueTask and ValueTask<T>, I've often encountered scenarios where I don't care about the result of a ValueTask<T>-returning method and just want to return back the task to be awaited further up the stack.
Unfortunately, this isn't possible:
public ValueTask DoSomething()
{
// Do a bunch of synchronous stuff here...
return DoSomethingElse(); // CS0029 - Cannot implicitly convert type 'System.Threading.Tasks.ValueTask<int>' to 'System.Threading.Tasks.ValueTask'
}
public ValueTask<int> DoSomethingElse()
{
// Do a bunch of synchronous stuff here...
return new ValueTask<int>(42);
}The workarounds I've found is to either make the calling method async, which introduces a bunch of state machinery:
-public ValueTask DoSomething()
+public async ValueTask DoSomething()
{
// Do a bunch of synchronous stuff here...
- return DoSomethingElse();
+ await DoSomethingElse();
}Or convert the ValueTask<T> to a Task<T> and wrap it in a ValueTask, which allocates a Task<T>:
public ValueTask DoSomething()
{
// Do a bunch of synchronous stuff here...
- return DoSomethingElse();
+ return new ValueTask(DoSomethingElse().AsTask());
}Are there any other workarounds I've missed?
Anyway, I think it would be nice if there was a quick way to convert a ValueTask<T> to ValueTask, without introducing async state machinery or allocate.
Either as an explicit method, or just an implicit conversion that throws away the ValueTask<T>'s _result field:
@@ -118,7 +118,7 @@ namespace System.Threading.Tasks
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private ValueTask(object obj, short token, bool continueOnCapturedContext)
+ internal ValueTask(object obj, short token, bool continueOnCapturedContext)
{
_obj = obj;
_token = token;
@@ -555,6 +555,11 @@ namespace System.Threading.Tasks
public static bool operator !=(ValueTask<TResult> left, ValueTask<TResult> right) =>
!left.Equals(right);
+ public static implicit operator ValueTask(ValueTask<TResult> task)
+ {
+ return new ValueTask(task._obj, task._token, task._continueOnCapturedContext);
+ }
+
/// <summary>
/// Gets a <see cref="Task{TResult}"/> object to represent this ValueTask.
/// </summary>There might be a really good reason why this conversion doesn't exist already, but I don't know the details so I though I would ask; would this be doable?
// @stephentoub