首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将ValueTask<T>转换为非泛型ValueTask

将ValueTask<T>转换为非泛型ValueTask
EN

Stack Overflow用户
提问于 2020-04-16 17:55:14
回答 2查看 506关注 0票数 3

这里提出的问题与一张在这里相同,目的是为它创造一个明确的解决方案。最准确的答案是Stephen自己在本期中,这正是关于这个问题的。“推荐的代码”如下:

代码语言:javascript
复制
public static ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
{
    if (valueTask.IsCompletedSuccessfully)
    {
        valueTask.GetResult();
        return default;
    }

    return new ValueTask(valueTask.AsTask());
}

这个答案并不是最新的-- ValueTask不公开一个GetResult() (只是一个结果属性)--问题是:

  • 我们是否需要从ValueTask中“提取”结果(以“释放”可能在此ValueTask下运行的IValueTaskSource )?
  • 如果是:
    • 上面缺少的是.GetAwaiter()调用吗?
    • 或者是一个对房产的假调用保证了var fake = valueTask.Result;的工作?一直都是?(我害怕死代码消除。)

  • 如果没有,那么像下面这样的直接实现是否足够(也是最优的)?
代码语言:javascript
复制
public static ValueTask AsNonGenericValueTask<T>( in this ValueTask<T> valueTask )
{
    return valueTask.IsCompletedSuccessfully ? default : new ValueTask( valueTask.AsTask() );
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-04-16 21:06:11

代码中缺少的是.GetAwaiter()

代码语言:javascript
复制
public static ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
{
    if (valueTask.IsCompletedSuccessfully)
    {
        valueTask.GetAwaiter().GetResult();
        return default;
    }

    return new ValueTask(valueTask.AsTask());
}

你在一定程度上是对的,因为你不在乎结果。但是您可能关心抛出的异常或取消,如果您不查询结果,就会错过这些异常或取消。

或者你可以这样写:

代码语言:javascript
复制
public static async ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
    => await valueTask;
票数 3
EN

Stack Overflow用户

发布于 2022-03-28 01:27:01

您可以使用以下两种方法:

代码语言:javascript
复制
valueTask.GetAwaiter().GetResult();

...or:

代码语言:javascript
复制
_ = valueTask.Result;

这两种委托都是底层IValueTaskSource.GetResult方法的,假设ValueTask<T>是由IValueTaskSource支持的。使用更短(第二)的方法应该会稍微更有效率,因为它只需要少调用一次方法。

你也可以完全忽略这个结果。不需要至少等待一次ValueTask<T>,或者至少检索一次其结果。这是完全有效的,得到一个ValueTask<T>,然后忘记它。有记录的限制是:

ValueTask<TResult>实例只能等待一次,..。

这是“只可能”,而不是“必须”。

不过,取得这个结果仍然是个好主意。通过检索结果,您将发出ValueTask<TResult>已被消耗的信号,因此可以重用底层的IValueTaskSource<T>。重用IValueTaskSource<T>实例可以提高ValueTask<T>-based实现的效率,因为它们分配内存的频率较低。为了获得一个想法,请看一下内部的System.Threading.Channels.AsyncOperation类。该类实现IValueTaskSource<TResult>接口。下面是如何实现GetResult

代码语言:javascript
复制
/// <summary>Gets the result of the operation.</summary>
/// <param name="token">The token that must match <see cref="_currentId"/>.</param>
public TResult GetResult(short token)
{
    if (_currentId != token)
    {
        ThrowIncorrectCurrentIdException();
    }

    if (!IsCompleted)
    {
        ThrowIncompleteOperationException();
    }

    ExceptionDispatchInfo? error = _error;
    TResult? result = _result;
    _currentId++;

    if (_pooled)
    {
        Volatile.Write(ref _continuation, s_availableSentinel); // only after fetching all needed data
    }

    error?.Throw();
    return result!;
}

将私有字段Action<object> _continuation设置为静态只读值s_availableSentinel允许后续异步操作重用AsyncOperation<TResult> (例如,ChannelReader.ReadAsync )。否则,下一个异步操作将分配一个新的AsyncOperation<TResult>实例。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61256813

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档