我正在研究Enumerable.ToLookup
API,它将可枚举序列转换为字典类型数据结构。更多细节可以在这里找到:
https://msdn.microsoft.com/en-us/library/system.linq.enumerable.tolookup(v=vs.110).aspx
ToDictionary API带来的唯一区别是,如果密钥选择器导致重复密钥,它就不会给出任何错误。我需要比较这两个API的延迟执行语义。 AFAIK ToDictionary
API导致立即执行序列,即它不遵循LINQ查询的延迟执行语义。任何人都可以帮我解决ToLookup
API的延迟执行行为吗?它与ToDictionary
API或其他任何不同?
答案 0 :(得分:3)
足够容易测试...
void Main()
{
var lookup = Inf().ToLookup(i => i / 100);
Console.WriteLine("if you see this, ToLookup is deferred"); //never happens
}
IEnumerable<int> Inf()
{
unchecked
{
for(var i=0;;i++)
{
yield return i;
}
}
}
总结一下,ToLookup
贪婪会消耗源序列而不会延期。
相反,GroupBy
运算符是延迟,因此您可以编写以下内容以免产生不良影响:
var groups = Inf().GroupBy(i => i / 100); //oops
但是,GroupBy
贪婪,因此当您枚举时,将消耗整个源序列。
这意味着
groups.SelectMany(g=>g).First();
也未能完成。
当您考虑分组问题时,很快就会发现,当将序列分成一系列组时,即使只有一个组完整而没有完全消耗整个序列,也不可能知道。 / p>
答案 1 :(得分:2)
答案 2 :(得分:0)
如果查看Enumerable.ToDictionary()和Enumerable.ToLookup()方法的参考实现源代码,您将看到两者最终都在源枚举上执行foreach
循环。这是确认在两种情况下都不会延迟执行源可枚举的一种方法。
但是我的意思是,答案是非常明显的,因为如果你从一个可枚举开始,并且该函数的返回值不再是可枚举的,那么很明显,它必须已被执行(消耗) ,不是吗?
(@spender在评论中指出的最后一段不准确)