ValueTask是否有类似于ContinueWith的方法?

4

如果一个API返回ValueTaskValueTask<T>,是否有方法对其执行ContinueWith,就像我可以使用Task做的那样?是否有适用于.NET Standard 2.0的微软提供的NuGet库来实现这一点?


1
ContinueWith 是遗留的 API。坦白地说,你根本不应该使用它。你应该同时使用 awaitvalue-task - Marc Gravell
3个回答

12
使用 valueTask.AsTask()AsTask() 是为像您这样的用例而设计的逃生口,ValueTask 的目的是尽可能避免分配内存,但如果您要在另一个线程上调用后续操作,那么您需要分配一些内存,最好分配给一个 Task<T>

7

Here you are:

public static async ValueTask ContinueWith<TResult>(this ValueTask<TResult> source,
    Action<ValueTask<TResult>> continuationAction)
{
    // The source task is consumed after the await, and cannot be used further.
    ValueTask<TResult> completed;
    try
    {
        completed = new(await source.ConfigureAwait(false));
    }
    catch (OperationCanceledException oce)
    {
        var tcs = new TaskCompletionSource<TResult>();
        tcs.SetCanceled(oce.CancellationToken);
        completed = new(tcs.Task);
    }
    catch (Exception ex)
    {
        completed = new(Task.FromException<TResult>(ex));
    }
    continuationAction(completed);
}

一个更简单的实现方法是在 await 之前 Preserve ValueTask<TResult>,然后使用保留的任务作为参数调用 continuationAction。即使任务成功完成,这样做也会导致内存分配。
我避免使用在取消时一行代码的 Task.FromCanceled 方法的原因是,该方法要求提供的 CancellationToken 已被取消,否则将抛出 ArgumentOutOfRangeException 异常。

3

我知道我发帖晚了,但是我还是想分享一下我采用的方法...

ValueTask<T> vt = ValueTaskTReturningMethod();
var awt = vt.GetAwaiter();
awt.OnCompleted(() => {
   T val = awt.GetResult();
   //code you want to execute after async operation completes
}

或者只需使用 T val = await vt; // 你想要执行的代码... - 更简单。 - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接