如何实现无需显式指定泛型参数的Task<IEnumerable<T>>扩展方法
我尝试为带有IEnumerable<T>类型参数的Task创建一个扩展方法,使其返回IAsyncEnumerable<T>以满足某接口要求,但尝试过程中持续报错。核心需求是:能否实现类似第一个示例的扩展方法,使其可作用于Task的类型参数的实现类(如List<T>、ICollection<T>),且无需显式指定扩展方法的泛型参数?
我创建的第一个扩展方法如下:
public static class EnumerableExtensions { public static async IAsyncEnumerable<T> GetAsyncEnumerable<T, TEnumerable>(this Task<TEnumerable> task) where TEnumerable : IEnumerable<T> { foreach (var item in await task) { yield return item; } } }
该方法可正常编译,但无法直接在ICollection<T>或List<T>等IEnumerable实现类的Task实例上调用:
var enumerable = Task.FromResult(new List<int>()).GetAsyncEnumerable();
会抛出错误:
The type arguments for method 'IAsyncEnumerable
Demo.EnumerableExtensions.GetAsyncEnumerable<T,TEnumerable>(this Task )' cannot be inferred from the usage. Try specifying the type arguments explicitly.
显式指定类型参数时可正常编译:
var enumerable = Task.FromResult(new List<int>()).GetAsyncEnumerable<int, List<int>>();
我还尝试了另一种变体,但同样无效:
public static class EnumerableExtensions { public static async IAsyncEnumerable<T> GetAsyncEnumerable<T>(this Task<IEnumerable<T>> task) { foreach (var item in await task) { yield return item; } } }
抛出的错误为:
The type arguments for method 'IAsyncEnumerable
Demo.EnumerableExtensions.GetAsyncEnumerable (this Task<IEnumerable >)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
方法1:通过变量类型提示编译器推断
不需要修改扩展方法,只需要在调用时给变量指定明确的IAsyncEnumerable<T>类型,编译器就能反向推断出泛型参数:
IAsyncEnumerable<int> enumerable = Task.FromResult(new List<int>()).GetAsyncEnumerable();
方法2:优化扩展方法实现,支持自动推断
调整扩展方法的泛型定义,让编译器能直接从Task的结果类型中推断出T:
public static class EnumerableExtensions { // 核心实现:处理Task<IEnumerable<T>>的情况 public static async IAsyncEnumerable<T> GetAsyncEnumerable<T>(this Task<IEnumerable<T>> task) { foreach (var item in await task) { yield return item; } } // 重载:处理Task<TEnumerable>的情况,自动转换为Task<IEnumerable<T>> public static IAsyncEnumerable<T> GetAsyncEnumerable<T>(this Task<TEnumerable> task) where TEnumerable : IEnumerable<T> { return task.ContinueWith(t => t.Result as IEnumerable<T>).GetAsyncEnumerable(); } }
这样调用时就不需要显式指定泛型参数,直接写:
var enumerable = Task.FromResult(new List<int>()).GetAsyncEnumerable();
方法3:简化扩展方法,利用隐式转换
只保留针对Task<IEnumerable<T>>的扩展方法,调用时通过AsEnumerable()将具体集合类型转为IEnumerable<T>,让编译器自动推断:
public static class EnumerableExtensions { public static async IAsyncEnumerable<T> GetAsyncEnumerable<T>(this Task<IEnumerable<T>> task) { foreach (var item in await task) { yield return item; } } } // 调用示例 var enumerable = Task.FromResult(new List<int>().AsEnumerable()).GetAsyncEnumerable();
内容的提问来源于stack exchange,提问作者Ben

