IEnumerable'da neden ForEach genişletme yöntemi yok?


389

Eksik Zipfonksiyon hakkında soru soran başka bir sorudan ilham alındı :

Neden sınıfta ForEachuzatma yöntemi yok Enumerable? Veya herhangi bir yerde? Bir ForEachyöntem alan tek sınıf List<>. Eksik olmasının bir nedeni var mı (performans)?


Muhtemelen daha önceki bir yazının ima ettiği gibi, foreach C # ve VB.NET'te (ve diğer birçoklarında) bir dil anahtar sözcüğü olarak desteklenir.
chrisb

2
Burada 'resmi cevap' bağlantısı ile ilgili soru stackoverflow.com/questions/858978/…
Benjol


Bence çok önemli bir nokta, bir foreach döngüsünün fark edilmesinin daha kolay olmasıdır. .ForEach (...) kullanırsanız, kodu gözden geçirdiğinizde bunu kaçırmak kolaydır. Performans sorunlarınız olduğunda bu önemli hale gelir. Tabii ki .ToList () ve .ToArray () aynı soruna sahiptir, ancak biraz farklı kullanılırlar. Başka bir neden, bir .ForEach'ta kaynak listesini değiştirmenin (öğeleri kaldırma / ekleme) daha yaygın olması olabilir, böylece artık "saf" bir sorgu olmaz.
Daniel Bişar

Paralelize kod ayıklarken, sık sık değiştirmeyi deneyin Parallel.ForEachiçin Enumerable.ForEachyok ikincisi yeniden keşfetmek için sadece. C # burada işleri kolaylaştırmak için bir hile kaçırdı.
Albay Panik

Yanıtlar:


198

Zaten çoğu zaman işi yapan dilde bir foreach ifadesi var.

Aşağıdakileri görmekten nefret ederim:

list.ForEach( item =>
{
    item.DoSomething();
} );

Onun yerine:

foreach(Item item in list)
{
     item.DoSomething();
}

İkincisi, yazılması biraz daha uzun olsa da, çoğu durumda daha net ve okunması daha kolaydır .

Ancak, bu konudaki tutumumu değiştirdiğimi itiraf etmeliyim; bir ForEach () uzantısı yöntemi bazı durumlarda gerçekten yararlı olacaktır.

Deyim ve yöntem arasındaki büyük farklar şunlardır:

  • Tip kontrolü: foreach çalışma zamanında yapılır, ForEach () derleme zamanındadır (Big Plus!)
  • Bir temsilci çağırmak için sözdizimi gerçekten çok daha basittir: objects.ForEach (DoSomething);
  • ForEach () zincirlenebilir: böyle bir özelliğin kötülük / kullanışlılığı tartışmaya açık olmasına rağmen.

Bunların hepsi burada birçok insan tarafından yapılan harika noktalar ve insanların neden işlevi kaçırdığını görebiliyorum. Microsoft'un sonraki çerçeve yinelemesinde standart bir ForEach yöntemi eklemesine aldırmam.


39
Buradaki cevap şu cevabı vermektedir: forums.microsoft.com/MSDN/… Temel olarak uzantı yöntemlerinin işlevsel olarak "saf" tutulmasına karar verildi. ForEach, amaç olmayan uzantı yöntemlerini kullanırken yan etkileri teşvik eder.
mancaus

17
C geçmişiniz varsa 'foreach' daha net görünebilir, ancak dahili yineleme niyetinizi daha açık bir şekilde belirtir. Bu, 'array.AsParallel (). ForEach (...)' gibi şeyler yapabileceğiniz anlamına gelir.
Jay Bazuzi

10
Tip kontrolüyle ilgili konunun doğru olduğundan emin değilim. foreacheğer numaralandırılabilir parametrelendirilmişse tip derleme zamanında kontrol edilir. Varsayımsal bir ForEachgenişletme yönteminde olduğu gibi, yalnızca jenerik olmayan koleksiyonlar için derleme zaman türü denetiminden yoksundur .
Richard Poole

49
Uzatma yöntemi gibi, nokta gösterimi ile zincir LINQ gerçekten faydalı olacaktır: col.Where(...).OrderBy(...).ForEach(...). Çok daha basit sözdizimi, gereksiz yerel değişkenler veya foreach () içinde uzun parantezler ile ekran kirliliği yok.
Jacek Gorgoń

22
"Aşağıdakileri görmekten nefret ediyorum" - Soru kişisel tercihlerinizle ilgili değildi ve yabancı hat beslemeleri ve yabancı bir çift ayraç ekleyerek kodu daha nefret ettin. O kadar nefret dolu değil list.ForEach(item => item.DoSomething()). Ve bunun bir liste olduğunu kim söyledi? Bariz kullanım durumu bir zincirin sonundadır; foreach ifadesiyle, tüm zinciri sonradan inve çok daha az doğal veya tutarlı olan blok içinde gerçekleştirilecek işlemi koymanız gerekir .
Jim Balter

73

ForEach yöntemi LINQ'dan önce eklenmiştir. ForEach uzantısı eklerseniz, uzantı yöntemleri kısıtlamaları nedeniyle hiçbir zaman Liste örnekleri için çağrılmaz. Bence eklenmemesinin sebebi mevcut olanla karışmamaktır.

Ancak, bu küçük hoş işlevi gerçekten kaçırırsanız, kendi sürümünüzü sunabilirsiniz

public static void ForEach<T>(
    this IEnumerable<T> source,
    Action<T> action)
{
    foreach (T element in source) 
        action(element);
}

11
Uzatma yöntemleri buna izin verir. Belirli bir yöntem adının zaten bir örnek uygulaması varsa, uzantı yöntemi yerine bu yöntem kullanılır. Böylece ForEach uzantı yöntemi uygulayabilir ve List <>.
Cameron MacFarland

3
Cameron, inan bana uzatma yöntemlerinin nasıl çalıştığını biliyorum :) Liste IEnumerable devralır, bu yüzden açık olmayan bir şey olacaktır.
aku

9
Uzantı Yöntemleri Programlama Kılavuzu'ndan ( msdn.microsoft.com/en-us/library/bb383977.aspx ): Arabirim veya sınıf yöntemiyle aynı ada ve imzalı bir uzantı yöntemi asla çağrılmaz. Bana çok açık geliyor.
Cameron MacFarland

3
Farklı bir şey mi konuşuyorum? Birçok sınıfta ForEach yöntemi olduğunda bunun iyi olmadığını düşünüyorum, ancak bazıları farklı çalışabilir.
aku

5
Liste <>. ForEach ve Array.ForEach hakkında dikkat edilmesi gereken ilginç bir şey, aslında foreach yapısını dahili olarak kullanmamalarıdır. Her ikisi de döngü için bir düz kullanır. Belki de bir performans meselesidir ( diditwith.net/2006/10/05/PerformanceOfForeachVsListForEach.aspx ). Ancak, Array ve List'in her ikisi de ForEach yöntemlerini uygularsa, IEnumerable <> için değilse de en azından IList <> için bir genişletme yöntemi uygulamamış olmaları şaşırtıcıdır.
Matt Dotson

53

Bu uzantı yöntemini yazabilirsiniz:

// Possibly call this "Do"
IEnumerable<T> Apply<T> (this IEnumerable<T> source, Action<T> action)
{
    foreach (var e in source)
    {
        action(e);
        yield return e;
    }
}

Artıları

Zincire izin verir:

MySequence
    .Apply(...)
    .Apply(...)
    .Apply(...);

Eksileri

Yinelemeyi zorlamak için bir şey yapana kadar aslında hiçbir şey yapmaz. Bu nedenle çağrılmamalıdır .ForEach(). .ToList()Sonunda yazabilir veya bu uzantı yöntemini de yazabilirsiniz:

// possibly call this "Realize"
IEnumerable<T> Done<T> (this IEnumerable<T> source)
{
    foreach (var e in source)
    {
        // do nothing
        ;
    }

    return source;
}

Bu, gönderim C # kitaplıklarından ayrılma için çok önemli olabilir; uzantı yöntemlerinize aşina olmayan okuyucular kodunuzu ne yapacağınızı bilemez.


1
İlk fonksiyonunuz 'realize' yöntemiyle aşağıdaki gibi yazılmışsa kullanılabilir:{foreach (var e in source) {action(e);} return source;}
jjnguy

3
Uygula yönteminiz yerine Seç'i kullanamaz mısınız? Bana öyle geliyor ki, her bir öğeye bir eylem uygulamak ve bunu vermek, Select'in tam olarak yaptığı şeydir. Ör.numbers.Select(n => n*2);
rasmusvhansen

1
Uygulamanın bu amaç için Select kullanmaktan daha okunabilir olduğunu düşünüyorum. Bir Select ifadesini okurken, "İçeriden bir şeyler al" olarak okudum.
Dr Rob Lang

2
@rasmusvhansen Aslında, Select()her öğeye bir işlev Apply()uygulayın Actionve her öğeye bir uygula ve orijinal öğeyi döndürdüğü işlevin değerini döndürür diyor .
NetMage

1
Bu eşdeğerdirSelect(e => { action(e); return e; })
Jim Balter

35

Buradaki tartışma cevap verir:

Aslında, tanık olduğum özel tartışma aslında işlevsel saflığa bağlıydı. Bir ifadede, yan etkilere sahip olmama konusunda sık sık varsayımlar vardır. ForEach'a sahip olmak, sadece onlara katlanmaktan ziyade yan etkileri davet ediyor. - Keith Farmer (Ortak)

Temel olarak genişletme yöntemlerinin işlevsel olarak "saf" tutulmasına karar verildi. ForEach, amaçlanmamış Numaralandırma uzantısı yöntemlerini kullanırken yan etkileri teşvik eder.


6
Ayrıca bkz . Blogs.msdn.com/b/ericlippert/archive/2009/05/18/… . Ddoing, diğer tüm dizi operatörlerinin dayandığı fonksiyonel programlama ilkelerini ihlal eder. Açıkça, bu yönteme yapılan bir çağrının tek amacı yan etkilere neden
olmaktır

7
Bu akıl yürütme tamamen sahte. Kullanım durumu yan etkileri ihtiyaç olduğunu ... ForEach olmadan, bir foreach döngü yazmak zorunda olduğunu. ForEach'ın varlığı yan etkileri teşvik etmez ve yokluğu onları azaltmaz.
Jim Balter

Uzantı yöntemini yazmanın ne kadar basit olduğu göz önüne alındığında, bunun dil standardı olmaması için hiçbir neden yoktur.
Kaptan Prinny

17

foreachÇoğu durumda yerleşik yapıyı kullanmanın daha iyi olduğunu kabul etsem de, ForEach <> uzantısındaki bu varyasyonun kullanımının, dizini düzenli olarak foreachkendimde yönetmek zorunda kalmaktan biraz daha hoş olduğunu düşünüyorum :

public static int ForEach<T>(this IEnumerable<T> list, Action<int, T> action)
{
    if (action == null) throw new ArgumentNullException("action");

    var index = 0;

    foreach (var elem in list)
        action(index++, elem);

    return index;
}
Misal
var people = new[] { "Moe", "Curly", "Larry" };
people.ForEach((i, p) => Console.WriteLine("Person #{0} is {1}", i, p));

Size verecekti:

Person #0 is Moe
Person #1 is Curly
Person #2 is Larry

Harika bir uzantı, ancak bazı belgeler ekleyebilir misiniz? Döndürülen değerin amaçlanan kullanımı nedir? Neden indeks özellikle int yerine var? Örnek kullanım?
Mark T

İşaret: Dönüş değeri listedeki öğelerin sayısıdır. Dizin , örtülü yazma özelliği sayesinde özellikle int olarak yazılmıştır.
Chris Zwiryk

@Chris, yukarıdaki kodunuza göre, dönüş değeri listedeki öğelerin sayısı değil, listedeki son değerin sıfır temelli dizinidir.
Eric Smith

@Chris, hayır değil: dizin, değer alındıktan sonra artırılır (postfix artışı), bu nedenle ilk öğe işlendikten sonra dizin 1 olur. Yani dönüş değeri gerçekten eleman sayımıdır.
MartinStettner

1
@ Martinart 5/16 tarihinde Eric Smith'in yorumu daha önceki bir versiyondan geliyordu. Doğru değeri döndürmek için 5/18 kodunu düzeltti.
Michael Blackburn

16

Bir çözüm yazmaktır .ToList().ForEach(x => ...).

profesyoneller

Anlaması kolay - okuyucunun yalnızca C # ile birlikte gelenleri bilmesi gerekir, herhangi bir ek uzantı yöntemi değil.

Sözdizimsel gürültü çok hafiftir (sadece biraz yabancı kod ekler).

Her ne kadar bir yerli .ForEach()tüm koleksiyonu gerçekleştirmek zorunda kalacağından , genellikle fazladan belleğe mal olmaz.

Eksileri

İşlem sırası ideal değildir. Bir elementi fark etmeyi, sonra ona göre hareket etmeyi ve tekrar etmeyi tercih ederim. Bu kod önce tüm unsurları gerçekleştirir, sonra her birine sırayla etki eder.

Listenin farkına varmak bir istisna atarsa, asla tek bir öğe üzerinde hareket edemezsiniz.

Sayım sonsuzsa (doğal sayılar gibi), şansınız kalmaz.


1
a) Bu soruya uzaktan bir cevap bile değildir. b) Bu yanıt, eğer Enumerable.ForEach<T>bir List<T>.ForEachyöntem olmasa da, bir yöntem olduğu belirtilirse daha açık olacaktır . c) "Yerel bir .ForEach () zaten tüm koleksiyonu gerçekleştirmek zorunda olduğundan, genellikle fazladan bellek maliyeti yoktur." - tam ve saçmalık. İşte Enumerable.ForEach <T> uygulanması, eğer C # eğer sağlarsa:public static void ForEach<T>(this IEnumerable<T> list, Action<T> action) { foreach (T item in list) action(item); }
Jim Balter

13

Her zaman kendimi merak ettim, bu yüzden bunu hep yanımda taşıyorum:

public static void ForEach<T>(this IEnumerable<T> col, Action<T> action)
{
    if (action == null)
    {
        throw new ArgumentNullException("action");
    }
    foreach (var item in col)
    {
        action(item);
    }
}

Güzel küçük uzatma yöntemi.


2
col null olabilir ... bunu da kontrol edebilirsin.
Amy B

Evet, kütüphaneme check-in yapıyorum, hızlı bir şekilde orada yaparken özledim.
Aaron Powell

Herkesin null için action parametresini kontrol etmesini ilginç buluyorum, ancak asla source / col parametresini kontrol etmiyorum.
Cameron MacFarland

2
Ben de bir istisna sonuçları da kontrol değil herkes herkes null için parametreleri kontrol ilginç buluyorum ...
oɔɯǝɹ

Bir şey değil. Null Ref özel durumu, hatalı olan parametrenin adını söylemez. Ayrıca döngüyü de kontrol edebilirsiniz, böylece col [index #] 'nin aynı nedenden dolayı boş olduğunu söyleyerek belirli bir Null Ref atabilirsiniz
Roger Willcocks

8

Bu nedenle, bir ForEach uzantı yönteminin LINQ uzantı yöntemleri gibi bir değer döndürmediği için uygun olmadığı hakkında birçok yorum yapılmıştır. Bu gerçek bir ifade olmakla birlikte, tamamen doğru değildir.

LINQ genişletme yöntemlerinin tümü, birlikte zincirlenebilmeleri için bir değer döndürür:

collection.Where(i => i.Name = "hello").Select(i => i.FullName);

Ancak, LINQ'nun genişletme yöntemleri kullanılarak uygulanması, genişletme yöntemlerinin aynı şekilde kullanılması ve bir değer döndürmesi gerektiği anlamına gelmez . Bir değer döndürmeyen ortak işlevselliği ortaya çıkarmak için bir uzantı yöntemi yazmak son derece geçerli bir kullanımdır.

ForEach ile ilgili özel tartışma, uzatma yöntemleriyle ilgili kısıtlamalara dayanarak (yani bir uzatma yönteminin aynı imzayla devralınan bir yöntemi asla geçersiz kılmayacağı), özel genişletme yönteminin çığır açan tüm sınıflarda mevcut olduğu bir durum olabilir. IEnumerable > Liste hariç >. Bu, yöntemler, genişletme yönteminin mi yoksa devralma yönteminin mi çağrıldığına bağlı olarak farklı davranmaya başladığında karışıklığa neden olabilir.<T<T


7

Önce (zincirlenebilir, ancak tembel bir şekilde değerlendirilmiş) Select, önce işleminizi yapabilir ve daha sonra kimliği iade edebilirsiniz (veya isterseniz başka bir şey)

IEnumerable<string> people = new List<string>(){"alica", "bob", "john", "pete"};
people.Select(p => { Console.WriteLine(p); return p; });

Hala Count()(afaik numaralandırmanın en ucuz işlemi) veya yine de ihtiyacınız olan başka bir işlemle değerlendirildiğinden emin olmanız gerekir.

Yine de standart kütüphaneye getirdi görmek isterdim:

static IEnumerable<T> WithLazySideEffect(this IEnumerable<T> src, Action<T> action) {
  return src.Select(i => { action(i); return i; } );
}

Yukarıdaki kod daha sonra people.WithLazySideEffect(p => Console.WriteLine(p))etkin bir şekilde foreach ile eşdeğer, ancak tembel ve zincirlenebilir hale gelir .


Fantastik, döndürülen bir seçimin böyle çalışacağını hiç tıklamadı. Yöntem sözdiziminin güzel bir kullanımı, bunu ifade sözdizimi ile yapabileceğinizi düşünmüyorum (dolayısıyla daha önce böyle düşünmedim).
Alex KeySmith

@AlexKeySmith Eğer C # dizisi gibi bir dizi işlecine sahipse ifade sözdizimi ile yapabilirsiniz. Ancak ForEach'ın bütün mesele, void türünde bir eylem gerçekleştirmesidir ve C # ifadelerinde void türlerini kullanamazsınız.
Jim Balter

imho, artık Selectyapması gerekeni artık yapmıyor. OP'nin istediği şey için kesinlikle bir çözüm - ancak konu okunabilirliği konusunda: hiç kimse seçimin bir işlevi yerine getirmesini beklemez.
Matthias Burger

@MatthiasBurger Yapması Selectgereken şeyi yapmazsa Select, çağıran kodla değil, Selectne Selectyaptığı üzerinde hiçbir etkisi olmayan uygulama ile ilgili bir sorundur .
Martijn


4

@Coincoin

Foreach eklenti yönteminin gerçek gücü, Action<>kodunuza gereksiz yöntemler eklemeden yeniden kullanılabilirliği içerir . 10 listeniz olduğunu ve bunlarda aynı mantığı gerçekleştirmek istediğinizi ve buna karşılık gelen bir işlevin sınıfınıza uymadığını ve yeniden kullanılmadığını varsayalım. Döngüler için on veya açık bir şekilde ait olmayan bir yardımcı olan genel bir işlev yerine, tüm mantığınızı tek bir yerde tutabilirsiniz ( Action<>.

Action<blah,blah> f = { foo };

List1.ForEach(p => f(p))
List2.ForEach(p => f(p))

vb...

Mantık tek bir yerde ve sınıfınızı kirletmediniz.


foreach (List1.Concat içinde var p (List2) .Concat (Liste3)) {... do şeyler ...}
Cameron MacFarland

O kadar basit olarak ise f(p), o zaman dışarıda bırakın { }için steno: for (var p in List1.Concat(List2).Concat(List2)) f(p);.
spoulson

3

LINQ genişletme yöntemlerinin çoğu sonuç döndürür. ForEach, hiçbir şey döndürmediği için bu desene uymaz.


2
ForEach, başka bir delege olan Action <T> 'i kullanıyor
Aaron Powell

2
Lepie'nin hakkı dışında, tüm Numaralandırılabilir uzantı yöntemleri bir değer döndürür, bu nedenle ForEach kalıba uymaz. Delegeler buna girmiyor.
Cameron MacFarland

Bir uzatma yönteminin bir sonuç döndürmesi gerekmiyorsa, sık kullanılan bir işlemi çağırmanın bir yolunu ekleme amacına hizmet eder
Aaron Powell

1
Gerçekten de, Slace. Peki ya bir değer döndürmezse?
TraumaPony

1
@Martijn iepublic IEnumerable<T> Foreach<T>(this IEnumerable<T> items, Action<T> action) { /* error check */ foreach (var item in items) { action(item); yield return item; } }
McKay

3

F # (.NET'in sonraki sürümünde olacak) varsa, aşağıdakileri kullanabilirsiniz:

Seq.iter doSomething myIEnumerable


9
Bu yüzden Microsoft, C # ve VB'de bir IEnumerable için bir ForEach yöntemi sağlamayı seçmedi, çünkü tamamen işlevsel olmayacaktı; yine de daha işlevsel dillerinde (# iter) F # sağladılar. Onların mantığı beni ima ediyor.
Scott Hutchinson

3

Kısmen, dil tasarımcıları ona felsefi bir bakış açısıyla katılmıyorlar.

  • Bir özelliğe sahip olmamak (ve test etmek ...) bir özelliğe sahip olmaktan daha az iştir.
  • Gerçekten daha kısa değil (olduğu yerde bazı geçiş fonksiyonu durumları var, ancak bu birincil kullanım olmayacak).
  • Amacı, linq ile ilgili olmayan yan etkilere sahip olmaktır.
  • Zaten sahip olduğumuz bir özellikle aynı şeyi yapmanın başka bir yolu var mı? (foreach anahtar kelimesi)

https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/


2

Bir şey döndürmek istediğinizde select komutunu kullanabilirsiniz. Bunu yapmazsanız, öncelikle koleksiyondaki hiçbir şeyi değiştirmek istemediğiniz için ToList'i kullanabilirsiniz.


a) Bu sorunun cevabı değildir. b) ToList, ek zaman ve bellek gerektirir.
Jim Balter

2

Bu konuda bir blog yazısı yazdım: http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx

Bu yöntemi .NET 4.0'da görmek istiyorsanız buraya oy verebilirsiniz: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=279093


bu hiç uygulandı mı? Hayal etmiyorum, ancak bu biletin yerini alan başka bir URL var mı? MS connect kullanımdan kaldırıldı
knocte


2

3.5'te, IEnumerable'a eklenen tüm genişletme yöntemleri LINQ desteği için vardır (System.Linq.Enumerable sınıfında tanımlandıklarına dikkat edin). Bu yazıda, foreach neden LINQ: Parallel.For?


2

Bu benim mi yoksa Liste <T>. Her zaman Linq tarafından eskimiş hale getirildi. Başlangıçta vardı

foreach(X x in Y) 

burada Y'nin IEnumerable (Pre 2.0) olması ve bir GetEnumerator () uygulaması gerekiyordu. Oluşturulan MSIL'a bakarsanız, bunun tam olarak aynı olduğunu görebilirsiniz.

IEnumerator<int> enumerator = list.GetEnumerator();
while (enumerator.MoveNext())
{
    int i = enumerator.Current;

    Console.WriteLine(i);
}

( MSIL için http://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspx adresine bakın )

Sonra DotNet2.0 Generics geldi ve Liste. Foreach her zaman Vistor deseninin bir uygulaması olduğumu hissetti, (bkz. Gamma, Helm, Johnson, Vlissides Tasarım Desenleri).

Şimdi elbette 3.5'te bunun yerine aynı etki için bir Lambda kullanabiliriz, örneğin bir örnek için http://dotnet-developments.blogs.techtarget.com/2008/09/02/iterators-lambda-and-linq-oh- benim/


1
"Foreach" için oluşturulan kod bir try-nihayet bloğu olması gerektiğine inanıyorum. Çünkü IEnumerator of T, ID arayüzünü devralır. Bu nedenle, oluşturulan son blokta, T örneğinin IEnumerator öğesinin Atılması gerekir.
Morgan Cheng

2

Aku'nun cevabını genişletmek istiyorum .

Bir yöntemi, yalnızca tüm numaralandırmayı tekrarlamadan yan etkisinin amacı için çağırmak istiyorsanız, bunu kullanabilirsiniz:

private static IEnumerable<T> ForEach<T>(IEnumerable<T> xs, Action<T> f) {
    foreach (var x in xs) {
        f(x); yield return x;
    }
}

1
Bu aynıSelect(x => { f(x); return x;})
Jim Balter

0

Hiç kimse, ForEach <T> öğesinin foreach anahtar kelimesinin çalışma zamanı denetlendiği yerde derleme zamanı türü denetimi ile sonuçlanmadığına işaret etmedi.

Her iki yöntem kodu kullanılan bazı refactoring yaptıktan sonra, ben foreach sorunları bulmak için test hataları / çalışma zamanı hataları avlamak zorunda kaldı .ForEach iyilik.


5
Gerçekten böyle mi? Daha foreachaz derleme zaman kontrolünün nasıl olduğunu göremiyorum . Elbette, koleksiyonunuz jenerik olmayan bir IEnumerable ise, döngü değişkeni bir olacaktır object, ancak aynı varsayımsal bir ForEachuzantı yöntemi için de geçerli olacaktır .
Richard Poole

1
Bu, kabul edilen cevapta belirtilmiştir. Ancak, bu sadece yanlış (ve yukarıdaki Richard Poole doğrudur).
Jim Balter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.