Skip to content

Provide conversion from ValueTask<T> to ValueTask #31503

@khellang

Description

@khellang

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions