为什么C#编译器会对这个嵌套的LINQ查询感到厌烦?

时间:2014-04-06 18:46:00

标签: c# linq

尝试编译以下代码,你会发现编译器需要> 3 GB的RAM(我机器上的所有可用内存)和很长的编译时间(实际上我在10分钟后得到IO异常)。< / p>

using System;
using System.Linq;

public class Test
{
    public static void Main()
    {
        Enumerable.Range(0, 1).Sum(a =>
        Enumerable.Range(0, 1).Sum(b =>
        Enumerable.Range(0, 1).Sum(c =>
        Enumerable.Range(0, 1).Sum(d =>
        Enumerable.Range(0, 1).Sum(e =>
        Enumerable.Range(0, 1).Sum(f =>
        Enumerable.Range(0, 1).Count(g => true)))))));
    }
}

有人可以解释这种奇怪的行为吗?

CS Version:     Microsoft (R) Visual C# Compiler version 4.0.30319.17929
OS Name:        Microsoft Windows 7 Ultimate
OS Version:     6.1.7601 Service Pack 1 Build 7601

Memory Usage

1 个答案:

答案 0 :(得分:40)

我认为它与类型推断和/或lambda生成有关(当类型推断必须与正常方向相反时),与重载决策相结合。不幸的是,只提供类型参数并不能帮助解决这种情况(可能还需要进行类型检查)。

下面的代码,在逻辑上应该是你的等效代码,在分析了lambda之后,编译没有问题:

static void Main()
{
    var x = Enumerable.Range(0, 1).Sum(a);
}

private static int a(int a)
{
    return Enumerable.Range(0, 1).Sum(b);
}
private static int b(int b)
{
    return Enumerable.Range(0, 1).Sum(c);
}
private static int c(int c)
{
    return Enumerable.Range(0, 1).Sum(d);
}
private static int d(int d)
{
    return Enumerable.Range(0, 1).Sum(e);
}
private static int e(int e)
{
    return Enumerable.Range(0, 1).Sum(f);
}
private static int f(int f)
{
    return Enumerable.Range(0, 1).Count(g);
}
private static bool g(int g)
{
    return true;
}

我相信Eric Lippert之前发布的类型推断是C#编译器中的一个地方,其中(某些问题)可能会迫使编译器尝试解决NP-Complete问题,而其唯一真正的策略(如此处)是蛮力。如果我能找到相关的参考资料,我会在这里添加。


我能找到的最佳参考是here,其中Eric正在讨论导致实际成本的重载解析工作 - 请记住,Enumerable.Sum有10个重载接受lambda /方法。