2011-05-27 1 views
6

Je suivant extrait de code C#Une variable locale ne peut être déclarée dans ce champ [expression Linq/Lambda]

static void Main() 
{ 
    var numbers = new[] { 1, 2, 3, 4, 5, 6 }; 

    var ngt5 = numbers.Where(n => n > 5); 

    var n = ngt5.First().ToString(); 

    Console.WriteLine(n, numbers); 
} 

Quand je compilait le code ci-dessus, je reçois l'erreur suivante

A variable locale appelée « n » ne peut pas être déclaré dans ce champ

+2

Quel est le contexte de ce code? – SirPentor

+0

@Tobias: J'ai modifié mon code –

Répondre

16

Votre problème est ici:

// Within your lambda you have an 'n'. 
var ngt5 = numbers.Where(n => n > 5); 

// And within the outer scope you also have an 'n'. 
var n = ngt5.First().ToString(); 

Pour comprendre pourquoi il en est un problème, considérez le code suivant:

int n = 1000; 
var evens = Enumerable.Range(1, 1000).Where(n => n % 2 == 0); 

L'expression n % 2 == 0 ci-dessus est ambiguë: qui n-nous parlons? Si nous parlons de la externen, puis n % 2 == 0 est toujours vrai que n est juste 1000 (et donc evens comprendra tous les nombres de 1 à 1000). D'un autre côté, si nous parlons du intérieurn, alors n % 2 == 0 ne sera vrai que pour les valeurs paires de n (et evens sera 2, 4, 6, ... 1000).

Le point important à réaliser est que les variables déclarées en dehors du lambda sont accessibles depuis l'intérieur du lambda.

int n = 0; 
Action incrementN =() => n++; // accessing an outer variable 
incrementN(); 
Console.WriteLine(n); // outputs '1' 

C'est pourquoi l'ambiguïté existe, et pourquoi elle n'est donc pas autorisée.


La solution est simplement de choisir un nom de variable différent pour votre lambda; par exemple:

var ngt5 = numbers.Where(x => x > 5); 
+0

@Dan: vous voulez dire que la variable lambda est globale? –

+1

@geek: Non, ce n'est pas global. Je vais mettre à jour ma réponse pour mieux expliquer ... –

+0

@Dan Tao: Ok monsieur –

0

Votre problème est que vous supposez que les fermetures sont des fonctions de première classe en C#, ce qui n'est pas le cas et j'aurais aimé que ce soit le cas.

Vous ne pouvez pas traiter la portée de la fermeture C# comme une fonction isolée.

Vous ne pouvez pas retourner une expression Linq compliquée en dehors de la portée actuelle.

JavaScript permet cette ambiguïté, qui permet d'écrire des fermetures sans aucune limite, ce qui rend les fonctions de fermeture de première classe de JavaScript.

Questions connexes