96 votes

Pourquoi le compilateur C # est-il devenu fou sur cette requête LINQ imbriquée?

Compiler le code suivant et vous verrez que le compilateur prend >3 GO de RAM (tous les libérer de la mémoire sur ma machine) et beaucoup de temps pour compiler (en fait je obtenir IO exception après 10 minutes).

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)))))));
    }
}

Quelqu'un peut-il expliquer ce curieux comportement?

CS Version: Microsoft (R) Visual C# version de Compilateur 4.0.30319.17929
Nom du système d'exploitation: Microsoft Windows 7 édition intégrale
OS Version: 6.1.7601 Service Pack 1 Build 7601

Memory Usage

40voto

Damien_The_Unbeliever Points 102139

Je crois que c'est lié à l'inférence de type et/ou lambda génération (lors de l'inférence de type a à aller dans la direction opposée à la normale), combinée avec la résolution de surcharge. Malheureusement, il suffit de fournir les paramètres de type n'aide pas la situation (où il sans doute encore a effectuer la vérification de type).

Le code suivant, qui devrait logiquement être l'équivalent du code de la vôtre, après lambdas ont été analysés, compile sans problème:

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;
}

Je crois que Eric Lippert a posté avant que l'inférence de type est l'un des endroits dans le compilateur C# où (certains problèmes) peut forcer le compilateur à essayer de résoudre un problème NP-Complet de problème et de sa seule réelle stratégie (comme ici) est la force brute. Si je peux trouver les références, je vais les ajouter ici.


La meilleure référence que je peux trouver est ici où Eric est de discuter le fait que c'est la résolution de surcharge de travail qui provoque le coût réel - n'oubliez pas, Énumérable.Somme a 10 surcharges qui acceptent de lambda/méthode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X