ToLookup是否强制立即执行序列

时间:2016-08-13 02:25:56

标签: c# .net linq

我正在研究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或其他任何不同?

3 个答案:

答案 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)

这有点覆盖here,但很难找到!

简而言之 - ToLookup不会推迟执行!

  • ToLookup() - &gt;立即执行
  • GroupBy()(及其他查询方法) - &gt;延期执行

答案 2 :(得分:0)

如果查看Enumerable.ToDictionary()Enumerable.ToLookup()方法的参考实现源代码,您将看到两者最终都在源枚举上执行foreach循环。这是确认在两种情况下都不会延迟执行源可枚举的一种方法。

但是我的意思是,答案是非常明显的,因为如果你从一个可枚举开始,并且该函数的返回值不再是可枚举的,那么很明显,它必须已被执行(消耗) ,不是吗?

(@spender在评论中指出的最后一段不准确)