IEnumerable için foreach'in LINQ eşdeğeri <T>


717

LINQ'da aşağıdakilerin eşdeğerini yapmak istiyorum, ancak nasıl olduğunu anlayamıyorum:

IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());

Gerçek sözdizimi nedir?


99
Eric Lippert'in "foreach" ve "ForEach" kelimelerini düşünün . Kullanmamak / tedarik etmemek için iyi bir gerekçe sağlar ForEach().

4
@pst: Bu uzantı yöntemlerini projelerime körü körüne yapıştırırdım. Bu yazı için teşekkürler.
Robin Maben

2
Orada MoreLINQ bir sahiptir ForEachuzantısı .
Uwe Keim

2
Çok seksi olmasa da, bu ToList ile bir kopya oluşturmadan bir satıra sığar -foreach (var i in items) i.Dostuff();
James Westgate

1
Bu bağlantılardan bazıları öldü! Bu kadar oylanan makale neydi?
Warren

Yanıtlar:


864

İçin herhangi bir ForEach uzantısı yoktur IEnumerable; sadece List<T>. Böylece yapabilirsin

items.ToList().ForEach(i => i.DoStuff());

Alternatif olarak, kendi ForEach uzantı yönteminizi yazın:

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

213
ToList () işlevine dikkat edin, çünkü ToList () dizinin performans ve bellek sorunlarına neden olabilecek bir kopyasını oluşturur.
decasteljau

15
".Foreach ()" in daha iyi olmasının birkaç nedeni vardır. 1. Çoklu iş parçacığı, PLINQ ile mümkündür. 2. İstisnalar, döngüdeki tüm istisnaları toplamak ve bir kerede atmak isteyebilirsiniz; ve bunlar gürültü kodları.
Dennis C

12
PLINQ ForAll değil ForEach kullanır, bu yüzden ForEach kullanmazsınız.
user7116

9
IENumerable<T>Uzantı yönteminde bir döndürmelisiniz . Gibi:public static IEnumerable<T> ForAll<T>(this IEnumerable<T> numeration, Action<T> action) { foreach (T item in enumeration) { action(item); } return enumeration; }
Kees C. Bakker

22
İlk durumda, geliştiricinin 1) neredeyse hiç yazma kaydetmediğini ve 2) gereksiz yere tüm diziyi atmadan önce bir liste olarak depolamak için gereksiz yere ayırdığını unutmayın.
LINQ'dan

364

Fredrik düzeltmeyi sağladı, ancak bunun neden başlangıçta çerçeve içinde olmadığını düşünmeye değer olabilir. Fikir LINQ sorgu operatörleri dünyaya makul bir işlevsel şekilde uygun, yan etkisi ücretsiz olması gerektiğine inanıyorum. Açıkça ForEach tam tersi - tamamen yan etkiye dayalı bir yapı.

Bu, bunun kararın arkasındaki felsefi nedenleri düşünerek kötü bir şey olduğunu söylemek değildir.


44
Ve yine, F # Seq.iter
Stephen Swensen

6
Bununla birlikte, LINQ işlevlerinin genellikle foreach () tarafından sağlanmamasını sağlayan çok kullanışlı bir şey vardır - Linq işlevleri tarafından alınan anonim işlev de parametre olarak bir dizin alabilir, buna karşılık foreach ile klasik (int i .. ) yapı. Ve fonksiyonel diller yan etkileri olan yinelemeye izin vermelidir - aksi takdirde onlarla hiç bir iota çalışma yapamazsınız :) Tipik fonksiyonel yöntemin orijinal numaralandırmayı değiştirmeden geri döndürmek olduğunu belirtmek isterim.
Walt W

3
@Walt: Kısmen kabul ettiğimden emin değilim, kısmen tipik bir gerçekten işlevsel yaklaşım böyle bir foreach kullanmaz ... daha çok LINQ gibi fonksiyonel bir yaklaşım kullanır ve yeni bir dizi yaratır.
Jon Skeet

12
@Stephen Swensen: evet, F # 'in Seq.iter' i var, ancak F # 'de değişmez veri yapıları var. bunlar üzerinde Seq.iter kullanırken orijinal Seq değiştirilmez; yan etkili elemanlara sahip yeni bir Seq döndürülür.
Anders

7
@Anders - Seq.iteryan etki unsurları ile yeni bir seq bile hiçbir şey döndürmez. Gerçekten sadece yan etkilerle ilgilidir. Düşünüyor olabilirsiniz Seq.map, çünkü Seq.itertam olarak bir ForEachuzatma yöntemine eşdeğerdir IEnumerabe<_>.
Joel Mueller

39

Güncelleme 7/17/2012: Görünüşe göre C # 5.0'dan itibaren foreach, aşağıda açıklanan davranış değiştirildi ve " iç içe lambda ifadesinde yineleme değişkeninin kullanımı foreachartık beklenmedik sonuçlar üretmiyor . " Bu yanıt C # ≥ 5.0 için geçerli değil .

@ John Skeet ve foreach anahtar kelimesini tercih eden herkes.

5.0'dan önceki C #'da "foreach" ile ilgili sorun, " anlama için" eşdeğerinin diğer dillerde nasıl çalıştığı ve nasıl çalışacağını beklediğim ile tutarsız olmasıdır (kişisel görüş burada sadece diğerleri tarafından belirtildiği için belirtilmiştir. okunabilirlik ile ilgili görüş). " Değiştirilmiş kapanışa erişim " ve " Zararlı sayılan döngü değişkeninin kapatılması " ile ilgili tüm soruları görün . Bu sadece "zararlı" çünkü "foreach" C # uygulanan yolu.

@Fredrik Kalseth'in cevabındaki işlevsel olarak eşdeğer uzatma yöntemini kullanarak aşağıdaki örnekleri alın.

public static class Enumerables
{
    public static void ForEach<T>(this IEnumerable<T> @this, Action<T> action)
    {
        foreach (T item in @this)
        {
            action(item);
        }
    }
}

Aşırı tartışılmış örnek için özür dilerim. Sadece Gözlemlenebilir'i kullanıyorum çünkü böyle bir şey yapmak tamamen zor değil. Açıkçası bu gözlemlenebilir yaratmanın daha iyi yolları var, sadece bir noktaya göstermeye çalışıyorum. Tipik olarak gözlemlenebilir öğeye abone olunan kod, eşzamansız olarak ve potansiyel olarak başka bir iş parçacığında yürütülür. "Foreach" kullanılıyorsa, bu çok garip ve potansiyel olarak deterministik olmayan sonuçlar doğurabilir.

"ForEach" uzantısı yöntemini kullanarak aşağıdaki test geçer:

[Test]
public void ForEachExtensionWin()
{
    //Yes, I know there is an Observable.Range.
    var values = Enumerable.Range(0, 10);

    var observable = Observable.Create<Func<int>>(source =>
                            {
                                values.ForEach(value => 
                                    source.OnNext(() => value));

                                source.OnCompleted();
                                return () => { };
                            });

    //Simulate subscribing and evaluating Funcs
    var evaluatedObservable = observable.ToEnumerable().Select(func => func()).ToList();

    //Win
    Assert.That(evaluatedObservable, 
        Is.EquivalentTo(values.ToList()));
}

Aşağıdakiler hatayla başarısız olur:

Beklenen: <0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ile eşdeğer> Ama şuydu: <9, 9, 9, 9, 9, 9, 9, 9, 9, 9>

[Test]
public void ForEachKeywordFail()
{
    //Yes, I know there is an Observable.Range.
    var values = Enumerable.Range(0, 10);

    var observable = Observable.Create<Func<int>>(source =>
                            {
                                foreach (var value in values)
                                {
                                    //If you have resharper, notice the warning
                                    source.OnNext(() => value);
                                }
                                source.OnCompleted();
                                return () => { };
                            });

    //Simulate subscribing and evaluating Funcs
    var evaluatedObservable = observable.ToEnumerable().Select(func => func()).ToList();

    //Fail
    Assert.That(evaluatedObservable, 
        Is.EquivalentTo(values.ToList()));
}

Yeniden şekillendirici uyarısı ne diyor?
19'da reggaeguitar

1
@reggaeguitar C # 5.0 yayınlanmadan önce, burada açıklanan davranışı değiştiren 7 veya 8 yıldır C # kullanmadım. O zaman bu uyarıyı verdi stackoverflow.com/questions/1688465/… . Yine de bu konuda uyarıda bulunduğundan şüpheliyim.
drstevens

34

İçin kullanılabilir olan FirstOrDefault()uzantıyı kullanabilirsiniz IEnumerable<T>. Yüklemden dönerek false, her öğe için çalıştırılacak, ancak aslında bir eşleşme bulamaması umurumda olmayacak. Bu ToList()ek yükü önleyecektir .

IEnumerable<Item> items = GetItems();
items.FirstOrDefault(i => { i.DoStuff(); return false; });

11
Ben de katılıyorum. Akıllıca küçük bir saldırı olabilir, ancak ilk bakışta, bu kod kesinlikle standart bir foreach döngüsüne kıyasla ne yaptığını net değil.
Connell

26
Ben çünkü süre downvote zorunda teknik olarak yerine çünkü doğru, gelecekteki öz ve tüm ardılları sonsuza dek nefret edecektir foreach(Item i in GetItems()) { i.DoStuff();}size daha fazla karakter aldı ve son derece kafa karıştırıcı yapılan
Mark Sowul

14
Tamam, ama prolly daha okunabilir bir kesmek:items.All(i => { i.DoStuff(); return true; }
nawfal

5
Bunun oldukça eski bir yazı olduğunu biliyorum, ama bunu da düşürmek zorunda kaldım. Bunun akıllıca bir hile olduğuna katılıyorum, ancak sürdürülemez. İlk bakışta, sadece listedeki ilk öğeyle bir şeyler yapıyor gibi görünüyor. Bu, kodlayıcıların nasıl çalıştığını ve ne yapması gerektiğini yanlış anlamalarıyla gelecekte daha fazla hataya neden olabilir.
Lee

4
Bu yan etki programlama ve IMHO önerilmez.
Anish

21

Fredrik'in yöntemini kullandım ve dönüş türünü değiştirdim.

Bu şekilde yöntem, diğer LINQ yöntemleri gibi ertelenmiş yürütmeyi destekler .

DÜZENLEME: Bu açık değilse, bu yöntemin herhangi bir kullanımı ToList () veya yöntemi numaralandırılabilir tam olarak çalışmaya zorlamak için başka bir yol ile bitmelidir . Aksi takdirde eylem gerçekleştirilmez!

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
    foreach (T item in enumeration)
    {
        action(item);
        yield return item;
    }
}

Ve işte görmenize yardımcı olacak test:

[Test]
public void TestDefferedExecutionOfIEnumerableForEach()
{
    IEnumerable<char> enumerable = new[] {'a', 'b', 'c'};

    var sb = new StringBuilder();

    enumerable
        .ForEach(c => sb.Append("1"))
        .ForEach(c => sb.Append("2"))
        .ToList();

    Assert.That(sb.ToString(), Is.EqualTo("121212"));
}

Sonunda ToList () öğesini kaldırırsanız, StringBuilder boş bir dize içerdiğinden sınamanın başarısız olduğunu görürsünüz. Çünkü hiçbir yöntem ForEach'ı numaralandırmaya zorlamamıştır.


Alternatif uygulamanız ForEachilginçtir, ancak List.ForEachimzası olan davranışıyla eşleşmez public void ForEach(Action<T> action). Ayrıca , imzası olan Observable.ForEachuzantının davranışı ile eşleşmez . Scala koleksiyonlarındaki eşdeğeri olan FWIW, tembel olanlar bile, C # 'da boşluğa eşdeğer bir dönüş tipine sahiptir. IObservable<T>public static void ForEach<TSource>(this IObservable<TSource> source, Action<TSource> onNext)ForEach
drstevens

Bu en iyi cevaptır: ertelenmiş uygulama + akıcı api.
Alexander Danilov

3
Bu, arama Selectile tam olarak aynı şekilde çalışır ToList. Amacı ForEacharamak zorunda kalmamaktırToList . Hemen yürütülmelidir.
t3chb0t

3
Yürütülmesini ertelenen bu "ForEach" a hemen uygulayan bir "ForEach" a sahip olmanın yararı nedir? Erteleme (ForEach'ın nasıl kullanılacağı konusunda elverişsizdir), ForEach'ın yalnızca Eylem'in yan etkileri [böyle bir Linq operatörüne karşı yapılan olağan şikayet] olması durumunda faydalı işler gerçekleştirmesi gerçeğini iyileştirmez. Nasıl yapar bu değişiklik yardımı? Buna ek olarak, eklenen "ToList ()", onu çalıştırmaya zorlamak için yararlı bir amaca hizmet etmez. Bu bir kaza olmasını bekliyor. "ForEach" noktası yan etkileridir. Döndürülmüş bir numaralandırma İSTİYORSANIZ, SELECT daha anlamlı olur.
ToolmakerSteve

20

Yan Etkilerinizi IEnumerable'ımdan uzak tutun

LINQ'da aşağıdakilerin eşdeğerini yapmak istiyorum, ancak nasıl olduğunu anlayamıyorum:

Diğerlerinin de burada ve yurtdışında işaret ettiği gibi LINQ ve IEnumerableyöntemlerin yan etkisiz olması beklenmektedir.

IEnumerable'daki her öğeye gerçekten "bir şeyler" yapmak istiyor musunuz? O zaman foreachen iyi seçimdir. Burada yan etkiler olduğunda insanlar şaşırmazlar.

foreach (var i in items) i.DoStuff();

Eminim yan etki istemezsin

Ancak tecrübelerime göre yan etkiler genellikle gerekli değildir. Çoğu zaman, Jon Skeet, Eric Lippert veya Marc Gravell tarafından bir StackOverflow.com yanıtıyla keşfedilmeyi bekleyen basit bir LINQ sorgusu vardır.

Bazı örnekler

Aslında sadece bir değer toplarsanız (biriktirirseniz), Aggregateuzantı yöntemini göz önünde bulundurmalısınız .

items.Aggregate(initial, (acc, x) => ComputeAccumulatedValue(acc, x));

Belki de yeni bir IEnumerable mevcut değerlerden .

items.Select(x => Transform(x));

Veya belki de bir arama tablosu oluşturmak istersiniz:

items.ToLookup(x, x => GetTheKey(x))

Olasılıklar listesi (tamamen amaçlanmamıştır) devam etmektedir.


7
Ah, bu nedenle Seçim Harita ve Toplama Küçült.
Darrel Lee

17

Harekete istiyorsanız numaralandırma sen gerektiğini rulo olarak verim her öğeyi.

public static class EnumerableExtensions
{
    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
    {
        foreach (var item in enumeration)
        {
            action(item);
            yield return item;
        }
    }
}

Bu, öğeyi iade ettiğinizde gerçekten bir ForEach değildir, daha çok bir Tap'a benzer.
EluciusFTW

10

Microsoft tarafından deneysel bir sürüm var LINQ için Etkileşimli Extensions (ayrıca Nuget üzerine , bkz RxTeams profili daha bağlantılar için). Kanal 9 video iyi açıklıyor.

Dokümanları yalnızca XML biçiminde sağlanır. Bu belgeleri daha okunaklı bir formatta olmasını sağlamak için Sandcastle'da çalıştırdım . Dokümanlar arşivini açın ve index.html dosyasını arayın .

Diğer pek çok güzellik arasında, beklenen ForEach uygulamasını sağlar. Bunun gibi bir kod yazmanıza izin verir:

int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8 };

numbers.ForEach(x => Console.WriteLine(x*x));

2
Etkileşimli Uzantılar için çalışan bağlantı: microsoft.com/download/en/details.aspx?id=27203
Maciek Świszczowski

8

PLINQ'ya (.Net 4.0'dan beri kullanılabilir) göre,

IEnumerable<T>.AsParallel().ForAll() 

IEnumerable üzerinde paralel bir foreach döngüsü yapmak.


eyleminiz threadsafe olduğu sürece, her şey iyidir. ancak gerçekleştirilecek güvenli olmayan bir işleminiz olursa ne olur? oldukça kargaşaya neden olabilir ...
shirbr510

2
Doğru. İş parçacığı güvenli değil, bazı iş parçacığı havuzundan farklı iş parçacıkları kullanılacak ... Ve cevabımı gözden geçirmem gerekiyor. Ben şimdi denediğinizde hiçbir ForEach () yoktur .. Ben bunu düşündüğümde ForEach ile bir Uzantı içeren kodum olmalı.
Wolf5

6

ForEach'ın amacı yan etkilere neden olmaktır. IEnumerable bir setin tembel numaralandırması içindir.

Bu kavramsal fark, düşündüğünüzde oldukça görünür.

SomeEnumerable.ForEach(item=>DataStore.Synchronize(item));

Bu, bir "sayım" veya "ToList ()" veya üzerinde bir şey yapana kadar yürütülmez. Açıkça ifade edilen şey bu değildir.

Yineleme zincirlerini ayarlamak, içeriği ilgili kaynaklarına ve koşullarına göre tanımlamak için IEnumerable uzantılarını kullanmalısınız. İfade Ağaçlar güçlü ve etkilidir, ancak doğalarını takdir etmeyi öğrenmelisiniz. Ve tembel değerlendirmeyi geçersiz kılan birkaç karakteri kaydetmek için sadece programlamak için değil.


5

Birçok insan bundan bahsetti, ama yazmak zorunda kaldım. Bu en açık / en okunabilir değil mi?

IEnumerable<Item> items = GetItems();
foreach (var item in items) item.DoStuff();

Kısa ve basit (st).


İlk satırın tamamını düşürebilir ve GetItems'i doğrudan foreach'te kullanabilirsiniz
timtam

3
Elbette. Anlaşılır olması için böyle yazılmıştır. Böylece hangi GetItems()yöntemin geri döndüğü açıktır .
Nenad

4
Şimdi yorumumu okuduğumda, bilmediğin bir şey söylüyorum gibi görünüyor. Öyle demek istemedim. Demek istediğim, bu foreach (var item in GetItems()) item.DoStuff();sadece bir güzellik.
Timtam

4

Şimdi seçeneği var ...

        ParallelOptions parallelOptions = new ParallelOptions();
        parallelOptions.MaxDegreeOfParallelism = 4;
#if DEBUG
        parallelOptions.MaxDegreeOfParallelism = 1;
#endif
        Parallel.ForEach(bookIdList, parallelOptions, bookID => UpdateStockCount(bookID));

Tabii ki, bu yepyeni bir iplik solucanı kutusu açar.

ps (Yazı tipleri için üzgünüm, sistemin karar verdiği şey)


4

Çok sayıda cevabın işaret ettiği gibi, böyle bir uzatma yöntemini kendiniz kolayca ekleyebilirsiniz. Ancak, bunu yapmak istemiyorsanız, BCL'de böyle bir şeyin farkında olmasam da, Systemzaten Reaktif Uzantıya bir referansınız varsa (ve eğer , sahip olmalıdır):

using System.Reactive.Linq;

items.ToObservable().Subscribe(i => i.DoStuff());

Yöntem adları biraz farklı olsa da, sonuç tam olarak aradığınız şeydir.


Görünüşe göre bu paket artık kullanımdan kaldırıldı
reggaeguitar

3

ForEach da Zincirleme olabilir , sadece eylemden sonra pileline geri koyun. akıcı kal


Employees.ForEach(e=>e.Act_A)
         .ForEach(e=>e.Act_B)
         .ForEach(e=>e.Act_C);

Orders  //just for demo
    .ForEach(o=> o.EmailBuyer() )
    .ForEach(o=> o.ProcessBilling() )
    .ForEach(o=> o.ProcessShipping());


//conditional
Employees
    .ForEach(e=> {  if(e.Salary<1000) e.Raise(0.10);})
    .ForEach(e=> {  if(e.Age   >70  ) e.Retire();});

Uygulamanın istekli bir sürümü.

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enu, Action<T> action)
{
    foreach (T item in enu) action(item);
    return enu; // make action Chainable/Fluent
}

Düzenleme: Bir Tembel versiyonu gibi, verim dönüşü kullanıyor bu .

public static IEnumerable<T> ForEachLazy<T>(this IEnumerable<T> enu, Action<T> action)
{
    foreach (var item in enu)
    {
        action(item);
        yield return item;
    }
}

Tembel versiyonun gerçekleşmesi GEREKİR , örneğin ToList (), aksi takdirde hiçbir şey olmaz. ToolmakerSteve'nin harika yorumlarına bakın.

IQueryable<Product> query = Products.Where(...);
query.ForEachLazy(t => t.Price = t.Price + 1.00)
    .ToList(); //without this line, below SubmitChanges() does nothing.
SubmitChanges();

Hem ForEach () hem de ForEachLazy () 'i kütüphanemde saklıyorum.


2
Bunu test ettin mi? Bu yöntemin sezgisel olarak davrandığı birkaç bağlam vardır. Daha iyi olurduforeach(T item in enu) {action(item); yield return item;}
Taemyr

2
Bu, birden fazla numaralandırma ile sonuçlanacaktır
regisbsb

İlginç. Yukarıdakileri ne zaman yapmak istediğimi düşünmek yerine 3 eylem dizisi için foreach (T item in enu) { action1(item); action2(item); action3(item); }mi? Tek, açık bir döngü. Ben eylem2 yapmaya başlamadan ÖNCE tüm eylem1 yapmak önemli olup olmadığını tahmin ediyorum .
ToolmakerSteve

@ Rm558 - "getiri getirisi" kullanarak yaklaşımınız. Pro: orijinal diziyi yalnızca bir kez numaralandırır, bu nedenle daha geniş bir numaralandırma aralığıyla doğru şekilde çalışır. Con: sonunda ".ToArray ()" unutursanız, hiçbir şey olmuyor. Başarısızlık açık olsa da, uzun süre göz ardı edilmez, bu yüzden büyük bir maliyet değildir. Bana "temiz hissetmez", ancak eğer biri bu yolda (bir ForEach operatörü) gidiyorsa, doğru bir ödünleşmedir.
ToolmakerSteve

1
Bu kod, işlem açısından güvenli değildir. Ya başarısız olursa ProcessShipping()? Alıcıya e-posta gönderirsiniz, kredi kartından ödeme alırsınız, ancak ona asla eşyalarını göndermez misiniz? Kesinlikle sorun istemek.
zmechanic

2

Bu "işlevsel yaklaşım" soyutlaması büyük zaman sızdırıyor. Dil seviyesindeki hiçbir şey yan etkileri engellemez. Kaptaki her öğe için lambda / delege çağrısı yapabildiğiniz sürece "ForEach" davranışını elde edersiniz.

Burada örneğin srcDictionary'ü destDictionary ile birleştirmenin bir yolu (anahtar zaten varsa - üzerine yazılır)

bu bir hack'tir ve herhangi bir üretim kodunda kullanılmamalıdır.

var b = srcDictionary.Select(
                             x=>
                                {
                                  destDictionary[x.Key] = x.Value;
                                  return true;
                                }
                             ).Count();

6
Bu feragatnameyi eklemeniz gerekiyorsa, muhtemelen göndermemelisiniz. Sadece benim fikrim.
Andrew Grothe

2
Bu ne kadar iyi foreach(var tuple in srcDictionary) { destDictionary[tuple.Key] = tuple.Value; }? Üretim kodunda değilse, bunu nerede ve neden kullanmalısınız?
Mark Sowul

3
Bu sadece prensipte mümkün olduğunu göstermek için. Ayrıca OP'nin istediği şeyi yapıyor ve açıkça üretimde kullanılmaması gerektiğini, hala meraklı ve eğitimsel değeri olduğunu belirtmiştim.
Zar Shardan

2

Jon Skeet'ten ilham alarak çözümünü aşağıdakilerle genişlettim:

Genişletme Yöntemi:

public static void Execute<TSource, TKey>(this IEnumerable<TSource> source, Action<TKey> applyBehavior, Func<TSource, TKey> keySelector)
{
    foreach (var item in source)
    {
        var target = keySelector(item);
        applyBehavior(target);
    }
}

Müşteri:

var jobs = new List<Job>() 
    { 
        new Job { Id = "XAML Developer" }, 
        new Job { Id = "Assassin" }, 
        new Job { Id = "Narco Trafficker" }
    };

jobs.Execute(ApplyFilter, j => j.Id);

. . .

    public void ApplyFilter(string filterId)
    {
        Debug.WriteLine(filterId);
    }


1

Bağlantı uzatma yöntemlerinin yan etkiden arındırılmış olması gerektiği fikrine katılmıyorum (sadece herhangi bir delege yan etki yapamayacağı için değil).

Aşağıdakileri göz önünde bulundur:

   public class Element {}

   public Enum ProcessType
   {
      This = 0, That = 1, SomethingElse = 2
   }

   public class Class1
   {
      private Dictionary<ProcessType, Action<Element>> actions = 
         new Dictionary<ProcessType,Action<Element>>();

      public Class1()
      {
         actions.Add( ProcessType.This, DoThis );
         actions.Add( ProcessType.That, DoThat );
         actions.Add( ProcessType.SomethingElse, DoSomethingElse );
      }

      // Element actions:

      // This example defines 3 distict actions
      // that can be applied to individual elements,
      // But for the sake of the argument, make
      // no assumption about how many distict
      // actions there may, and that there could
      // possibly be many more.

      public void DoThis( Element element )
      {
         // Do something to element
      }

      public void DoThat( Element element )
      {
         // Do something to element
      }

      public void DoSomethingElse( Element element )
      {
         // Do something to element
      }

      public void Apply( ProcessType processType, IEnumerable<Element> elements )
      {
         Action<Element> action = null;
         if( ! actions.TryGetValue( processType, out action ) )
            throw new ArgumentException("processType");
         foreach( element in elements ) 
            action(element);
      }
   }

Örneğin gösterdiği şey, gerçekten, bir eylemi tanımlayan değeri çevirmek ve çevirmek için büyük bir anahtar yapısı yazmak zorunda kalmadan, bir dizi öğe üzerinde yan etkileri olan birçok olası eylemden birini çağırmaya izin veren bir tür geç bağlamadır. karşılık gelen yönteme.


9
Bir genişletme yönteminin yan etkilere sahip olup olamayacağı ve olması gerekip gerekmediği arasında bir fark vardır. Sadece bunun olabileceğini belirtiyorsunuz, ancak yan etkilere sahip olmamasını önermek için çok iyi nedenler olabilir. Fonksiyonel programlamada, tüm fonksiyonlar yan etkisizdir ve fonksiyonel programlama yapılarını kullandıklarını varsaymak isteyebilirsiniz.
Dave Van den Eynde

1

Akıcı kalmak için böyle bir numara kullanılabilir:

GetItems()
    .Select(i => new Action(i.DoStuf)))
    .Aggregate((a, b) => a + b)
    .Invoke();

0

VB.NET için şunları kullanmalısınız:

listVariable.ForEach(Sub(i) i.Property = "Value")

NOT: Bu, yalnızca Listveya işaretine sahipseniz derlenir IList. Genel olarak IEnumerable, kabul edilen yanıtın ForEach genişletme yönteminin VB eşdeğerini yazın.
ToolmakerSteve

-1

Yine başka bir ForEachörnek

public static IList<AddressEntry> MapToDomain(IList<AddressModel> addresses)
{
    var workingAddresses = new List<AddressEntry>();

    addresses.Select(a => a).ToList().ForEach(a => workingAddresses.Add(AddressModelMapper.MapToDomain(a)));

    return workingAddresses;
}

4
Ne hafıza kaybı. Bu, bir listeye eklemek için ToList'i çağırır. Bu neden sadece adres döndürmüyor. (A => MapToDomain (a)) öğesini seçin?
Mark Sowul
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.