上写的不多ManualResetValueTaskSourceCore<TResult>
。它本质上是一个TaskCompletionSource<T>
but for ValueTask<T>
。
它真的打算在像你的计时器这样的类型中使用,但如果你想将它用作外部方法,你可以为它创建一个包装器:
public sealed class ManualResetValueTaskSource<T> : IValueTaskSource<T>, IValueTaskSource
{
private ManualResetValueTaskSourceCore<T> _logic; // mutable struct; do not make this readonly
public bool RunContinuationsAsynchronously
{
get => _logic.RunContinuationsAsynchronously;
set => _logic.RunContinuationsAsynchronously = value;
}
public void Reset() => _logic.Reset();
public void SetResult(T result) => _logic.SetResult(result);
public void SetException(Exception error) => _logic.SetException(error);
short IValueTaskSource.Version => _logic.Version;
short IValueTaskSource<T>.Version => _logic.Version;
void IValueTaskSource.GetResult(short token) => _logic.GetResult(token);
T IValueTaskSource<T>.GetResult(short token) => _logic.GetResult(token);
ValueTaskSourceStatus IValueTaskSource.GetStatus(short token) => _logic.GetStatus(token);
ValueTaskSourceStatus IValueTaskSource<T>.GetStatus(short token) => _logic.GetStatus(token);
void IValueTaskSource.OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => _logic.OnCompleted(continuation, state, token, flags);
void IValueTaskSource<T>.OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => _logic.OnCompleted(continuation, state, token, flags);
}
然后您可以这样使用它(为简单起见删除了取消):
ValueTask Delay(TimeSpan duration)
{
ITimer timer = timerFactory.Create();
var vts = new ManualResetValueTaskSource<object>();
TimerElapsed eventHandler = null;
eventHandler = (_, __) =>
{
timer.Elapsed -= eventHandler;
vts.SetResult(null);
};
timer.Elapsed += eventHandler;
timer.Start(duration);
return new ValueTask(vts);
}
请注意,由于这是一个外部方法,您仍将分配ManualResetValueTaskSource<T>
(以及委托)。所以这并不能真正给你买任何东西,我会选择在TaskCompletionSource<T>
这里使用。当您添加CancellationToken
支持并且必须处理计时器触发 ( vts.SetResult
) 和取消 ( vts.SetException
) 之间的竞争条件时尤其如此,因为我很确定每个 ValueTask 操作应该只发生其中一个,并且没有Try*
变体我们的ManualResetValueTaskSource<T>
喜欢TaskCompletionSource<T>
有。
ValueTask
真的是为了成为一等公民;即,理想情况下,您将更新实际的计时器实现(和接口)以支持ValueTask Delay(TimeSpan)
其自己的类而不是外部方法。在计时器实例内部,它可以重用ValueTask
支持类型(ManualResetValueTaskSource<T>
),它可以知道何时调用Reset
,并且可以完全避免委托/事件。