2011-08-20 16 views
5

Bu kodu dikkate alın.Foreach ve list.ForEach() arasında kapaklar nasıl değişir?

 var values = new List<int> {123, 432, 768}; 

     var funcs = new List<Func<int>>(); 

     values.ForEach(v=>funcs.Add(()=>v)); 

     funcs.ForEach(f=>Console.WriteLine(f()));//prints 123,432,768 

     funcs.Clear(); 

     foreach (var v1 in values) 
     { 
      funcs.Add(()=>v1); 
     } 

     foreach (var func in funcs) 
     { 
      Console.WriteLine(func()); //prints 768,768,768 
     } 

nedeniyle kapatma değişkenin ikinci foreach baskılar 768 3 kez lambda tarafından yakalanan biliyoruz. İlk durumda neden olmaz? foreach anahtar kelimesi Foreach yönteminden nasıl farklıdır? Sadece bir değişkeni tanıtır i values.ForEach

cevap

9

foreach yapınca ifade değerlendirilir BEACUSE mı. Her defasında lambda parametre değişkeni "taze" iken.

olduğunu
foreach (var v1 in values) // v1 *same* variable each loop, value changed 
{ 
    var freshV1 = v1; // freshV1 is *new* variable each loop 
    funcs.Add(() => freshV1); 
} 

foreach (var func in funcs) 
{ 
    Console.WriteLine(func()); //prints 123,432,768 
} 

,

foreach (T v in ...) { } 

olarak düşünülebilir:

T v; 
foreach(v in ...) {} 

Mutlu kodlama ile

karşılaştırın.

+1

Teşekkürler. Yazma için +1. –

6

fark foreach döngü içinde, çekilen bir tek değişken v1 var olmasıdır. Bu değişken, values içinde her bir değerin üstündedir - ancak'u kullanarak sadece kullanıyorsunuzdur. Bu, her seferinde yalnızca son değeri göreceğimiz anlamına gelir.

sürümünüzde, her yineleme yeni bir değişkeni (f parametresi) tanıtır - böylece her bir lambda ifadesi, hiçbir zaman değerde değişmeyen ayrı bir değişkeni yakalar.

Eric Lippert'in blogged about this vardır - ancak bu davranışı 'un C# sürümünün gelecekteki sürümlerinde değiştirebileceğini unutmayın.

+0

"foreach" semantiklerini anlıyorum. Fakat 'List .ForEach'da, üçüncü satırdaki gibi 'v' değişkeni her yineleme için yeni oluşturuldu mu demek istiyorsunuz? –

+0

@Ashley: Evet, çünkü lambda ifadesi için bir parametre. Aynı delege iki kez çağırmış olsanız ve * lambda ifadesi * değeri değiştirilmiş olsa bile, bu herhangi bir değişiklik yaratmaz - çünkü bu yakalanan bir değişken değil, yalnızca bir temsilci parametresidir. –

+0

@Jon, büyük regresyonlar yapmadan bu davranışı değiştirmeleri mümkün mü? – FuleSnabel