[英]Convert a ValueTask<T> to a non generic ValueTask
这里提出的问题与此处的问题相同,旨在为其创建一个明确的解决方案。 最准确的答案是 Stephen Toub 本人在本期中正是关于这个问题的。 “推荐代码”如下:
public static ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
{
if (valueTask.IsCompletedSuccessfully)
{
valueTask.GetResult();
return default;
}
return new ValueTask(valueTask.AsTask());
}
这个答案不是最新的 - ValueTask 不公开 GetResult() (只有一个 Result 属性) - 问题是:
.GetAwaiter()
调用吗?var fake = valueTask.Result;
? 总是? (我害怕死代码消除。)public static ValueTask AsNonGenericValueTask<T>( in this ValueTask<T> valueTask )
{
return valueTask.IsCompletedSuccessfully ? default : new ValueTask( valueTask.AsTask() );
}
该代码中缺少的是.GetAwaiter()
:
public static ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
{
if (valueTask.IsCompletedSuccessfully)
{
valueTask.GetAwaiter().GetResult();
return default;
}
return new ValueTask(valueTask.AsTask());
}
你部分正确,因为你不关心结果。 但是您可能会关心如果您不查询结果会错过的抛出异常或取消。
或者你可以这样写:
public static async ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
=> await valueTask;
您可以使用:
valueTask.GetAwaiter().GetResult();
...或者:
_ = valueTask.Result;
这两个都委托给基础IValueTaskSource<T>.GetResult
方法,假设ValueTask<T>
由IValueTaskSource<T>
支持。 使用更短的(第二种)方法应该稍微更有效,因为它涉及更少的方法调用。
您也可以完全忽略获取结果。 没有要求必须至少等待ValueTask<T>
一次,或者必须至少检索一次其结果。 交给ValueTask<T>
然后忘记它是完全有效的。 记录的限制是:
ValueTask<TResult>
实例只能等待一次,[...]
这是“只能” ,而不是“必须” 。
尽管如此,获得结果仍然是一个好主意。 通过检索结果,您表示ValueTask<TResult>
已被使用,因此可以重用底层的IValueTaskSource<T>
。 重用IValueTaskSource<T>
实例使基于ValueTask<T>
的实现更加高效,因为它们分配 memory 的频率较低。 要获得一个想法,请查看内部System.Threading.Channels.AsyncOperation<TResult>
class。此 class 实现了IValueTaskSource<TResult>
接口。 以下是GetResult
的实现方式:
/// <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
设置为 static 只读值s_availableSentinel
允许AsyncOperation<TResult>
被后续异步操作重用(例如ChannelReader.ReadAsync
)。 否则下一个异步操作将分配一个新的AsyncOperation<TResult>
实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.