使用ManualResetValueTaskSourceCore时ValueTask无法完成的问题
问题分析与解决:ManualResetValueTaskSourceCore 无法完成的问题
你的代码核心问题出在值类型的拷贝捕获上:ManualResetValueTaskSource<T>是struct值类型,Task.Run的lambda表达式捕获的是该实例的副本。后续调用SetResult(123)仅修改了副本的状态,而Main方法中等待的原实例状态从未更新,导致ValueTask永远无法完成。如果在await前调用SetResult,是直接修改原实例,所以能正常触发完成。
解决方案
最直接可靠的修复方式是将ManualResetValueTaskSource<T>从struct改为class,这样捕获的是实例引用,所有操作都会作用在同一个对象上:
internal class ManualResetValueTaskSource<T> : IValueTaskSource<T> { private ManualResetValueTaskSourceCore<T> _taskSource = new(); public short Version => _taskSource.Version; public ManualResetValueTaskSource() { _taskSource.RunContinuationsAsynchronously = true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ValueTask<T> GetTask() => new(this, _taskSource.Version); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void SetResult(T result) => _taskSource.SetResult(result); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void Reset() => _taskSource.Reset(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public T GetResult(short token) => _taskSource.GetResult(token); [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTaskSourceStatus GetStatus(short token) => _taskSource.GetStatus(token); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => _taskSource.OnCompleted(continuation, state, token, flags); } internal static class Program { private static async Task Main() { var mre = new ManualResetValueTaskSource<int>(); Task.Run(async () => { await Task.Delay(250); mre.SetResult(123); }); var result = await mre.GetTask(); Console.WriteLine(result); } }
如果一定要保留值类型,可以通过引用类型包装(比如数组)避免拷贝问题,但这种方式代码冗余且易出错,不推荐在实际场景中使用。
内容的提问来源于stack exchange,提问作者Fionn
相关产品推荐
相关产品推荐

