c# - 如何定义接受任何生成 IEnumerable<T> 的任务的函数?

标签 c# .net task-parallel-library async-await

我正在寻找一个函数来接受任何产生 IEnumerable<T> 的任务.为了说明,请考虑以下函数签名。

void DoWork<TElement>(Task<IEnumerable<TElement>> task)
{ }

现在,我想按如下方式调用此方法:

Task<int[]> task = Task.FromResult(new[] { 1, 2, 3 });
DoWork(task);

显然,这行不通,因为两个 Task类型不相同,并且任务不存在协方差。但是,我想知道是否有一些聪明的技巧可以让它发挥作用,灵感来自以下示例。

async Task<IEnumerable<int>> GetTask()
{
    return await Task.FromResult(new int[] { 1, 2, 3 });
}

在这里,await正在使用内联任务的结果有效地创建一个新任务,因此产生了类型转换的错觉。

举个更详细的例子,我想允许用户调用DoWork没有太多的转化负担:

// Service proxy method
Task<int[]> GetInts()
{
    // simplified for brevity
    return Task.FromResult(new[] { 1, 2, 3 });
}

// Service proxy method
Task<long[]> GetLongs()
{
    // simplified for brevity
    return Task.FromResult(new[] { 100L, 200L, 300L });
}

async Task<IEnumerable<T>> DoWork<T>(Func<Task<IEnumerable<T>>> getData,
                                     Func<T, bool> predicate)
{
    return (await getData()).Where(predicate);
}

// GOAL:
DoWork(GetInts, i => i % 2 == 0);
DoWork(GetLongs, l => l % 40 == 0);

最佳答案

您可以再引入一个 Type 参数并执行如下操作:

async Task<IEnumerable<TElement>> DoWork<T, TElement>(Func<Task<T>> getData,
                              Func<TElement, bool> predicate) where T : IEnumerable<TElement>
{
    return (await getData()).Where(predicate);
}

Task<int[]> GetInts()
{
    return Task.Run(() => new[] { 1, 2, 3 });
}

Task<long[]> GetLongs()
{
    return Task.Run(() => new[] { 100L, 200L, 300L });
}

那么你可以

static void Main()
{
    var ints = DoWork<int[], int>(GetInts, i => i % 2 == 0).Result;
    var longs = DoWork<long[], long>(GetLongs, i => i % 2 == 0).Result;
}

或者如 OP 在评论中所述,如果您指定 TElement,您可以让编译器推断类型明确地。

var ints = DoWork(GetInts, (int i) => i % 2 == 0).Result;

您的代码自 Task<T> 起无效在 T 上不是“协变的” .您可能知道类不能是协变的。

关于c# - 如何定义接受任何生成 IEnumerable<T> 的任务的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25221385/

相关文章:

c# - 如何根据单词中的给定索引找到单词的开始和结束索引?

c# - 为什么这段代码在将近一年的时间里运行良好却无法正常工作

c# - TPL ContinueWith 方法的用途是什么?

c# - 与巨大的数据流异步

c# - 带 Moq 的 MV3 测试项目,使用特定表达式时如何返回对象?

c# - 为什么 MapPoint.Route.Calculate() 比应用程序本身的计算慢得多?

python - 检测 (x, y) 数据中的区域

c# - 指定单个方法作为多个 Controller URL 的目标

c# - 如何取消并发的繁重任务?

c# - 为什么 EnumerableRowCollection<DataRow>.Select() 不能这样编译?