2009-12-10 8 views
4

Je suis très jeune avec les expressions lambda en C#, et j'ai du mal à conceptualiser comment elles sont stockées/récupérées dans une collection.Récupérer des expressions lambda d'une collection

J'essaye de créer par programme une liste de 10 Funcs x => x + 1, x => x + 2, etc. comme test. Ma sortie désirée est 0,1,2,3,4,5,6,7,8,9

Voici mon code pour que:

var list = new List<Func<int, int>>(); 
for (int i = 0; i < 10; i++) 
{  
    Func<int, int> func = x => x + i; 
    Console.WriteLine("a) " + func.Invoke(0)); //returns 0,1,2,3,4,5,6,7,8,9 

    list.Add(func); 
    Console.WriteLine("b) " + list[i].Invoke(0)); //returns 0,1,2,3,4,5,6,7,8,9 
} 

foreach (var func in list) //returns 10,10,10,10,10,10,10,10,10,10 
    Console.WriteLine("c) " + func.Invoke(0)); 

for(int i = 0; i < list.Count; i++) //returns 10,10,10,10,10,10,10,10,10,10 
    Console.WriteLine("d) " + list[i].Invoke(0)); 

Je reçois les mêmes résultats en substituant un tableau Func pour la liste [Func].

Qu'est-ce qui me manque?

Répondre

7

Marque i local au lambda en le copiant dans une nouvelle variable:

var list = new List<Func<int, int>>(); 
for (int i = 0; i < 10; i++) 
{ 
    var temp = i; 
    Func<int, int> func = x => x + temp; 
    Console.WriteLine("a) " + func.Invoke(0)); //returns 0,1,2,3,4,5,6,7,8,9 

    list.Add(func); 
    Console.WriteLine("b) " + list[i].Invoke(0)); //returns 0,1,2,3,4,5,6,7,8,9 
} 

foreach (var func in list) //returns 0,1,2,3,4,5,6,7,8,9 
    Console.WriteLine("c) " + func.Invoke(0)); 

for (int i = 0; i < list.Count; i++) //returns 0,1,2,3,4,5,6,7,8,9 
    Console.WriteLine("d) " + list[i].Invoke(0)); 
+0

Aha! Merci Monsieur. – bufferz

6
+0

Merci d'avoir posté ce lien. Intéressant comment C# est un peu enfermé dans cette mise en garde, donc les développeurs qui ont dépendu de maintenir la dernière valeur de i (dans mon cas) n'ont pas leurs programmes cassés. – bufferz

+2

Où par "intéressant" vous voulez dire "bizarre" ennuyeux ". :-) –

4

Votre problème est que la L'expression lambda capture la variable que vous avez utilisée pour la définir.

Depuis la boucle entière généré les actions de liste la même variable, tous les délégués rentreront 10.

Pour résoudre ce problème, déclarez une variable séparée à l'intérieur de la boucle de production, l'assigner à i, puis utilisez dans l'expression lambda.

Par exemple:

var list = new List<Func<int, int>>(); 
for (int dontUse = 0; dontUse < 10; dontUse++) { 
    var i = dontUse; 

    Func<int, int> func = x => x + i; 
    list.Add(func); 
} 

foreach (var func in list) 
    Console.WriteLine("c) " + func(0)); 

Pour plus d'informations, consultez this blog post

Par ailleurs, lorsque vous appelez les délégués, vous n'avez pas besoin d'écrire func.Invoke(params); vous pouvez simplement écrire func(params).

+0

C'était une photo-finish pour les 3 bonnes réponses à ma question principale, mais +1 pour votre dernier commentaire sur func (params) Merci! – bufferz