c# - 多次枚举返回任务的Linq Select查询
问题描述
我有一个 linq 查询,它返回一个任务对象并将其存储在IEnumerable
. 由于某种原因,选择查询一直在枚举,直到任务开始或完成(我认为,很难调试)。
查询非常简单:
Context.RetrieveDataTasks = retrievableProducts.Select(product => Context.HostController.RetrieveProductDataFiles(product));
签名的地方RetrieveProductDataFiles
是:
public Task RetrieveProductDataFiles(IProduct product)
在这种情况下,retrievableProducts 是 1 个产品的列表:
var retrievableProducts = products
.Where(product => AFancyButIrrelevantClause)
.ToList();
我不介意将代码重写为 foreach 循环,在该循环中我手动填充一个新列表以避免此问题,但我想了解为什么选择查询继续执行。我认为这与等待激活的任务有关,但我不知道为什么会导致这种情况。
编辑:
为了完整起见,我希望上面的代码与以下代码完全相同:
var retrievableDataTasks = new List<Task>();
foreach (var product in retrievableProducts)
{
retrievableDataTasks.Add(Context.HostController.RetrieveProductDataFiles(product));
}
Context.RetrieveDataTasks = retrievableDataTasks;
虽然使用 a 的构造foreach
完全符合我的期望:它填充了一个任务列表(在这种特定情况下是 1 个任务的列表),并且该任务执行一次。在使用Select
查询构造时,一遍又一遍地启动相同的 1 任务。
我希望我提供的代码足够清楚,期待了解为什么选择查询的行为不同(以及如果可能的话,如何避免它发生)。
解决方案
使用“ToList”会强制迭代器遍历所有集合,即使您认为您说“只需给我集合中的前两项”。如果该集合有 1000 个元素,您将迭代该集合,直到到达最后一个项目,它仍然会给您 2 个元素。
您可以通过使用 foreach 语句或 LINQ 查询来使用迭代器方法。foreach 循环的每次迭代都会调用迭代器方法。在迭代器方法中到达 yield return 语句时,返回表达式,并保留代码中的当前位置。下次调用迭代器函数时,将从该位置重新开始执行。
在您实例化添加到其中的列表的方法中,您需要稍微改进以使用收益返回,因此,不要分配不需要分配的数据。LINQ 方法是惰性求值的,这意味着在您尝试具体化结果(例如 ToList)之前不会为数据分配任何内存。当您在您的 LINQ 方法中时,您获得的唯一内存使用量是当前迭代,而不是您集合中的所有内容。
假设使用以下代码片段来帮助您。
private static IEnumerable<Product> GetMyProducts(IEnumerable<Product> products, bool AFancyButIrrelevantClause)
{
foreach(var product in products)
{
if(AFancyButIrrelevantClause)
yield return product;
}
}
或者直接在 LINQ 中更简洁:
products.Where(product => AFancyButIrrelevantClause)
推荐阅读
- c# - 正则表达式,从文件名中提取日期
- java - 为什么在嵌入式模式下尝试启动 apache Drill 时出现错误?
- gitlab - Gitlab管道连接符号未显示
- r - R中基于不规则间隔的生存数据表示
- json - 如何将 actix_web::web::Bytes 转换为 json?
- opencv - 有谁知道opencv中以下不推荐使用的函数的新名称?
- scala - 为什么 Scala Option.tapEach 返回 Iterable,而不是 Option?
- reactjs - 卸载组件时,其他组件中的钩子状态更改不是永久性的
- firebase - Firebase 动态链接:无法从短信点击
- react-native - NSMutableDictionary 无法转换为 ASAuthorizationAppleIDRequest