如何适配Task<T>实现协变接口且不丢失async/await语法支持?
完整实现方案
你猜测的没错,.NET 原生已经提供了AsyncTaskMethodBuilder<T>类型,我们直接将JobBuilder<T>的所有逻辑委托给该类型即可,完全复用原生Task<T>的所有行为逻辑,不需要自己重新实现异步状态机调度。
第一步:修正接口定义(修复笔误)
using System.Runtime.CompilerServices; [AsyncMethodBuilder(typeof(JobBuilder<>))] public interface IAsyncJob<out T> { IAwaiter<T> GetAwaiter(); } public interface IAwaiter<out T> : ICriticalNotifyCompletion { bool IsCompleted { get; } T GetResult(); }
第二步:实现Awaiter和Job包装类
// 值类型避免额外堆分配,性能开销几乎可以忽略 public struct Awaiter<T> : IAwaiter<T> { private readonly TaskAwaiter<T> _origin; public Awaiter(TaskAwaiter<T> origin) => _origin = origin; public bool IsCompleted => _origin.IsCompleted; public T GetResult() => _origin.GetResult(); public void OnCompleted(Action continuation) => _origin.OnCompleted(continuation); public void UnsafeOnCompleted(Action continuation) => _origin.UnsafeOnCompleted(continuation); } public struct Job<T> : IAsyncJob<T> { private readonly Task<T> _task; public Job(Task<T> task) => _task = task; public IAwaiter<T> GetAwaiter() => new Awaiter<T>(_task.GetAwaiter()); // 可选:加个隐式转换方便用 public static implicit operator Job<T>(Task<T> task) => new(task); }
第三步:完整实现JobBuilder
public class JobBuilder<T> { // 直接委托原生Task构建器,100%复用原生行为 private readonly AsyncTaskMethodBuilder<T> _nativeBuilder = AsyncTaskMethodBuilder<T>.Create(); public static JobBuilder<T> Create() => new(); public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine => _nativeBuilder.Start(ref stateMachine); public void SetStateMachine(IAsyncStateMachine stateMachine) => _nativeBuilder.SetStateMachine(stateMachine); public void SetResult(T result) => _nativeBuilder.SetResult(result); public void SetException(Exception exception) => _nativeBuilder.SetException(exception); public IAsyncJob<T> Task => new Job<T>(_nativeBuilder.Task); public void AwaitOnCompleted<TAwaiter, TStateMachine>( ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine => _nativeBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine => _nativeBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); }
第四步:可选扩展方法(方便转换)
public static class AsyncJobExtensions { public static IAsyncJob<T> ToAsyncJob<T>(this Task<T> task) => new Job<T>(task); }
功能验证
所有原生Task<T>支持的行为(异常传播、取消处理、同步上下文调度等)都可以正常使用,同时完全满足协变需求:
class A {} class B : A {} // async返回IAsyncJob<T>完全正常 async IAsyncJob<B> GetBAsync() { await Task.Delay(100); return new B(); } // 协变场景 IAsyncJob<B> bJob = GetBAsync(); IAsyncJob<A> aJob = bJob; A result = await aJob; // 接口层级协变也完全支持 public interface IJobAsyncGetter<out T> { IAsyncJob<T> GetAsync(); } IEnumerable<IJobAsyncGetter<B>> bList = Enumerable.Empty<IJobAsyncGetter<B>>(); IEnumerable<IJobAsyncGetter<A>> aList = bList; // 编译完全通过
内容的提问来源于stack exchange,提问作者Valentyn Zakharenko
相关产品推荐
相关产品推荐

