LINQ IEnumerable <T> के लिए फॉर्च्यूनर के बराबर है


717

मैं LINQ में निम्न के बराबर करना चाहता हूँ, लेकिन मैं यह पता नहीं लगा सकता कि:

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

वास्तविक वाक्यविन्यास क्या है?


99
एरिक लिपर्ट द्वारा "फॉरच" बनाम "फॉरएच" पर विचार करें । यह उपयोग / आपूर्ति नहीं करने के लिए अच्छा औचित्य प्रदान करता है ForEach()

4
@ पीएसटी: मैंने अपनी परियोजनाओं में इस विस्तार विधियों को आँख बंद करके इस्तेमाल किया। उस लेख के लिए धन्यवाद।
रॉबिन माबेन

2
नहीं है MoreLINQ जो एक है ForEachविस्तार
उवे कीम

2
जब तक बहुत सेक्सी नहीं, यह एक लाइन पर टॉलिस्ट के माध्यम से एक प्रतिलिपि बनाए बिना फिट बैठता है -foreach (var i in items) i.Dostuff();
जेम्स वेस्टगेट

1
इनमें से कुछ लिंक मृत हैं! क्या लेख था जो इतना मतदान किया गया था!
वॉरेन

जवाबों:


863

कोई ForEach एक्सटेंशन नहीं है IEnumerable; केवल के लिए List<T>। तो आप कर सकते हैं

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

वैकल्पिक रूप से, अपना स्वयं का ForEach एक्सटेंशन विधि लिखें:

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

213
ToList () के साथ सावधान रहें, क्योंकि ToList () अनुक्रम की एक प्रति बनाता है, जो प्रदर्शन और स्मृति समस्याओं का कारण बन सकता है।
डिकैस्टेलजॉ

15
ऐसे कुछ कारण हैं जिनकी वजह से ".Foreach ()" बेहतर होगा। 1. बहु सूत्रण, PLINQ द्वारा संभव है। 2. अपवाद, आप लूप में सभी अपवाद एकत्र करना चाहते हैं और इसे एक ही बार में फेंक सकते हैं; और वे शोर कोड हैं।
डेनिस सी

12
PLINQ ForAll का उपयोग नहीं करता है, जिसके कारण आप ForEach का उपयोग नहीं करेंगे।
user7116

9
आपको IENumerable<T>एक्सटेंशन विधि में वापस लौटना चाहिए । जैसे:public static IEnumerable<T> ForAll<T>(this IEnumerable<T> numeration, Action<T> action) { foreach (T item in enumeration) { action(item); } return enumeration; }
कीस सी। बक्कर

22
ध्यान दें कि पहले मामले में डेवलपर 1) लगभग कोई टाइपिंग नहीं बचाता है और 2) अनावश्यक रूप से इसे दूर फेंकने से पहले पूरे अनुक्रम को सूची के रूप में संग्रहीत करने के लिए मेमोरी आवंटित करता है। LINQ
मार्क सोउल

364

फ्रेड्रिक ने फिक्स प्रदान किया है, लेकिन यह विचार करने योग्य हो सकता है कि इसके साथ शुरू करने के लिए रूपरेखा में क्यों नहीं है। मेरा मानना ​​है कि विचार यह है कि LINQ क्वेरी ऑपरेटर्स को साइड-इफ़ेक्ट-फ़्री होना चाहिए, दुनिया को देखने का एक उचित कार्यात्मक तरीका है। स्पष्ट रूप से ForEach इसके विपरीत है - विशुद्ध रूप से साइड-इफ़ेक्ट-आधारित निर्माण।

यह कहना नहीं है कि यह एक बुरी बात है - निर्णय के पीछे दार्शनिक कारणों के बारे में सोचना।


44
और फिर भी, F # में Seq.iter है
स्टीफन

6
हालाँकि, एक बहुत ही उपयोगी चीज है जो LINQ फ़ंक्शन आमतौर पर प्रदान करता है कि foreach () नहीं है - Linq फ़ंक्शन द्वारा लिया गया अनाम फ़ंक्शन एक पैरामीटर के रूप में एक इंडेक्स भी ले सकता है, जबकि foreach के साथ आपको क्लासिक के लिए पुनर्निर्माण करना होगा (int i) ) निर्माण करता है। और कार्यात्मक भाषाओं को साइड इफेक्ट्स की अनुमति देने की अनुमति है - अन्यथा आप उनके साथ काम का एक कोटा कभी नहीं कर सकते :) मैं यह बताना चाहूंगा कि विशिष्ट कार्यात्मक विधि मूल गणना को अपरिवर्तित वापस करना होगा।
वॉल्ट डब्ल्यू

3
@Walt: मुझे अभी भी यकीन नहीं है कि मैं सहमत हूं, आंशिक रूप से क्योंकि एक सामान्य रूप से कार्यात्मक दृष्टिकोण इस तरह से फॉर्च्यूनर का उपयोग नहीं करेगा ... यह एक नया अनुक्रम बनाते हुए LINQ जैसे कार्यात्मक दृष्टिकोण का उपयोग करेगा।
जॉन स्कीट

12
@ स्टीफन स्वेनसेन: हाँ, F # में Seq.iter है, लेकिन F # में अपरिवर्तनीय डेटा संरचनाएं भी हैं। इन पर Seq.iter का उपयोग करते समय, मूल Seq को संशोधित नहीं किया गया है; साइड-इफेक्टेड तत्वों के साथ एक नया Seq वापस आ गया है।
एंडर्स

7
@ एंडर्स - Seq.iterकुछ भी वापस नहीं करते हैं, अकेले साइड-इफेक्टेड तत्वों के साथ एक नया seq करते हैं। यह वास्तव में दुष्प्रभाव के बारे में है। आप के बारे में सोच रहे हो सकता है Seq.map, क्योंकि Seq.iterपर एक ForEachविस्तार विधि के बराबर है IEnumerabe<_>
जोएल म्यूलर

39

अद्यतन 7/17/2012: जाहिरा तौर पर C # 5.0 के रूप में, foreachनीचे वर्णित व्यवहार को बदल दिया गया है और " नेस्टेड लैम्ब्डा अभिव्यक्ति में एक पुनरावृत्ति चर का उपयोग foreachअब अप्रत्याशित परिणाम नहीं देता है। " यह उत्तर C # ≥ 5.0 पर लागू नहीं होता है। ।

@ जॉन स्कीट और हर कोई जो फ़ॉरवर्ड कीवर्ड पसंद करता है।

5.0 से पहले C # में "foreach" के साथ समस्या यह है कि यह असंगत है कि कैसे "समझ के लिए समकक्ष" अन्य भाषाओं में काम करता है, और इसके साथ मैं कैसे काम करने की उम्मीद करूंगा (व्यक्तिगत राय यहां केवल इसलिए बताई गई है क्योंकि अन्य ने उनका उल्लेख किया है पठनीयता के संबंध में राय)। " संशोधित क्लोजर एक्सेस " के साथ-साथ " हानिकारक समझे जाने वाले लूप चर पर समापन " से संबंधित सभी प्रश्नों को देखें । यह केवल "हानिकारक" है क्योंकि जिस तरह से "foreach" C # में लागू किया गया है।

@Fredrik Kalseth के उत्तर में कार्यात्मक समतुल्य विस्तार विधि का उपयोग करके निम्नलिखित उदाहरण लें।

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

अतिविशिष्ट उदाहरण के लिए क्षमा याचना। मैं केवल ऑब्जर्वेबल का उपयोग कर रहा हूं क्योंकि यह पूरी तरह से ऐसा कुछ करने के लिए तैयार नहीं है। जाहिर है इस अवलोकन को बनाने के बेहतर तरीके हैं, मैं केवल एक बिंदु को प्रदर्शित करने का प्रयास कर रहा हूं। आमतौर पर अवलोकन योग्य सदस्यता वाला कोड एसिंक्रोनस रूप से निष्पादित किया जाता है और संभावित रूप से किसी अन्य थ्रेड में। यदि "फॉर्च्यूनर" का उपयोग किया जाता है, तो यह बहुत ही अजीब और संभावित गैर-नियतात्मक परिणाम उत्पन्न कर सकता है।

"ForEach" एक्सटेंशन विधि का उपयोग करके निम्नलिखित परीक्षण पास होता है:

[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()));
}

निम्नलिखित त्रुटि के साथ विफल रहता है:

अपेक्षित: <0, 1, 2, 3, 4, 5, 6, 7, 8, 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()));
}

क्या कहता है पुनर्जीवन चेतावनी?
रेगेगिटेर

1
@reggaeguitar मैंने C # 5.0 का उपयोग करने से पहले 7 या 8 वर्षों में C # का उपयोग नहीं किया है, जिसने यहां वर्णित व्यवहार को बदल दिया है। जिस समय इसने यह चेतावनी दी है stackoverflow.com/questions/1688465/… । मुझे संदेह है कि यह अभी भी इस पर चेतावनी देता है।
ड्रमस्टेन्स

34

आप FirstOrDefault()एक्सटेंशन का उपयोग कर सकते हैं , जो इसके लिए उपलब्ध है IEnumerable<T>falseविधेय से लौटकर , यह प्रत्येक तत्व के लिए चलाया जाएगा लेकिन यह ध्यान नहीं रखेगा कि यह वास्तव में एक मैच नहीं है। इससे ToList()ओवरहेड से बचा जा सकेगा ।

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

11
मैं भी सहमत हूँ। यह एक चतुर छोटी हैक हो सकती है, लेकिन पहली नजर में, यह कोड स्पष्ट नहीं है कि यह क्या कर रहा है, निश्चित रूप से एक मानक फ़ॉरेस्ट लूप की तुलना में।
कॉनेल

26
मुझे foreach(Item i in GetItems()) { i.DoStuff();}
नीचा दिखाना

14
ठीक है, लेकिन prolly अधिक पठनीय हैक:items.All(i => { i.DoStuff(); return true; }
nawfal

5
मुझे पता है कि यह एक काफी पुरानी पोस्ट है, लेकिन मुझे इसे भी कम करना पड़ा। मैं मानता हूं कि यह एक चतुर चाल है, लेकिन यह बनाए रखने योग्य नहीं है। पहली नज़र में ऐसा लगता है कि यह केवल सूची में पहले आइटम के साथ कुछ कर रहा है। यह कोडर गलतफहमी से भविष्य में अधिक बग पैदा कर सकता है कि यह कैसे कार्य करता है और यह क्या करने वाला है।
ली

4
यह साइड इफेक्ट प्रोग्रामिंग है और IMHO हतोत्साहित करता है।
अनिश

21

मैंने फ्रेड्रिक का तरीका अपनाया और रिटर्न टाइप को संशोधित किया।

इस तरह, विधि अन्य LINQ विधियों की तरह आस्थगित निष्पादन का समर्थन करती है ।

संपादित करें: यदि यह स्पष्ट नहीं था, तो इस पद्धति का कोई भी उपयोग टोलिस्ट () या किसी भी अन्य तरीके से पूरा करने योग्य विधि पर काम करने के लिए बाध्य होना चाहिए । अन्यथा, कार्रवाई नहीं की जाएगी!

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

और यहाँ यह देखने में मदद करने के लिए परीक्षण है:

[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"));
}

यदि आप अंत में ToList () को हटाते हैं , तो आप परीक्षण को विफल होते देखेंगे क्योंकि StringBuilder में एक खाली स्ट्रिंग है। ऐसा इसलिए है क्योंकि किसी भी विधि ने ForEach को गणना करने के लिए मजबूर नहीं किया है।


आपका वैकल्पिक कार्यान्वयन ForEachदिलचस्प है, हालांकि यह List.ForEachकिसके हस्ताक्षर के व्यवहार से मेल नहीं खाता है public void ForEach(Action<T> action)। यह Observable.ForEachएक्सटेंशन के व्यवहार से मेल नहीं खाता है IObservable<T>, जिसके हस्ताक्षर हैं public static void ForEach<TSource>(this IObservable<TSource> source, Action<TSource> onNext)। एफडब्ल्यूआईडब्ल्यू, ForEachस्काला संग्रह पर बराबर, यहां तक ​​कि जो आलसी हैं, उनमें भी रिटर्न प्रकार है जो सी # में शून्य के बराबर है।
drstevens

यह सबसे अच्छा जवाब है: आस्थगित निष्पादन + धाराप्रवाह एपीआई।
अलेक्जेंडर डेनिलोव

3
यह ठीक उसी तरह काम करता है जैसे कि कॉलिंग के Selectसाथ ToListForEachकॉल करने के लिए नहीं करने का उद्देश्य है ToList। इस पर तुरंत अमल होना चाहिए।
t3chb0t

3
इस "फॉरएच" के होने का क्या लाभ होगा, जिसका निष्पादन स्थगित हो जाता है, बनाम जो तुरंत निष्पादित होता है? पता करें (जो कि फॉरएच का उपयोग कैसे किया जाता है, इस बात में असुविधाजनक है) इस तथ्य की पुष्टि नहीं करता है कि फॉरएच केवल उपयोगी कार्य करता है यदि एक्शन के साइड-इफेक्ट [सामान्य शिकायत जो इस तरह के लाइनक ऑपरेटर के खिलाफ की गई हो]। तो, यह परिवर्तन कैसे मदद करता है ? इसके अलावा, जोड़ा गया "ToList ()" इसे निष्पादित करने के लिए मजबूर करने के लिए, कोई उपयोगी उद्देश्य नहीं देता है। यह एक दुर्घटना होने की प्रतीक्षा कर रहा है। "ForEach" का बिंदु इसके दुष्प्रभाव हैं। यदि आप लौटे हुए प्रतिज्ञान चाहते हैं, तो चयन अधिक समझ में आता है।
टूलमेकरसैट

20

अपने साइड इफेक्ट्स को मेरे IEnumerable से बाहर रखें

मैं LINQ में निम्न के बराबर करना चाहता हूँ, लेकिन मैं यह पता नहीं लगा सकता कि:

जैसा कि अन्य लोगों ने यहां और विदेशों में बताया है कि LINQ और IEnumerableतरीके साइड-इफ़ेक्ट फ्री होने की उम्मीद है।

क्या आप वास्तव में IEnumerable में प्रत्येक आइटम के लिए "कुछ करना" चाहते हैं? फिर foreachसबसे अच्छा विकल्प है। जब साइड इफेक्ट होते हैं तो लोग आश्चर्यचकित नहीं होते।

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

मुझे यकीन है कि आप एक साइड-इफ़ेक्ट नहीं चाहते हैं

हालांकि मेरे अनुभव में साइड-इफेक्ट्स की आवश्यकता नहीं होती है। अधिक से अधिक बार नहीं वहाँ एक सरल LINQ क्वेरी के लिए इंतजार कर रहा है साथ ही StackOverflow.com उत्तर के साथ जॉन स्कीट, एरिक लिपर्ट, या मार्क ग्रेवेल ने बताया कि आप क्या चाहते हैं!

कुछ उदाहरण

यदि आप वास्तव में केवल कुछ एकत्र कर रहे हैं (जमा कर रहे हैं) तो आपको Aggregateविस्तार विधि पर विचार करना चाहिए ।

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

शायद आप IEnumerableमौजूदा मूल्यों से एक नया बनाना चाहते हैं।

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

या शायद आप एक लुक-अप तालिका बनाना चाहते हैं:

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

संभावनाओं की सूची (पूरी तरह से इरादा नहीं) पर और पर चला जाता है।


7
आह, सेलेक्ट मैप है, और एग्रीगेट कम है।
डारेल ली

17

यदि आप गणन के रूप में कार्य करना चाहते हैं तो आपको प्रत्येक आइटम का उत्पादन करना चाहिए ।

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;
        }
    }
}

यह वास्तव में एक ForEach नहीं है जब आप आइटम वापस करते हैं, तो यह एक टैप की तरह अधिक होता है।
एलुयूसफेटडब्ल्यू

10

Microsoft की इंटरएक्टिव एक्सटेंशन्स द्वारा LINQ ( नूगेट पर भी देखें, RxTeams की प्रोफाइल को अन्य लिंक्स के लिए देखें ) एक प्रायोगिक रिलीज़ है । चैनल 9 वीडियो यह अच्छी तरह से बताते हैं।

इसके डॉक्स केवल एक्सएमएल फॉर्मेट में दिए गए हैं। मैंने सैंडकैसल में इस प्रलेखन को चलाने के लिए इसे और अधिक पठनीय प्रारूप में रखने की अनुमति दी है। डॉक्स संग्रह को अनज़िप करें और index.html खोजें

कई अन्य अच्छाइयों के बीच, यह अपेक्षित ForEach कार्यान्वयन प्रदान करता है। यह आपको इस तरह कोड लिखने की अनुमति देता है:

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

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

2
इंटरएक्टिव एक्सटेंशन के लिए काम कर रहे लिंक: microsoft.com/download/en/details.aspx?id=27203
Maciek iewiszczowski

8

PLINQ के अनुसार (.Net 4.0 के बाद से उपलब्ध), आप कर सकते हैं a

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

एक IEnumerable पर एक समानांतर foreach पाश करने के लिए।


जब तक आपकी क्रिया थ्रेडसेफ़ है, तब तक सब अच्छा है। लेकिन क्या होगा यदि आपके पास प्रदर्शन करने के लिए एक गैर-थ्रेडसेफ़ कार्रवाई है? यह काफी हाथापाई का कारण बन सकता है ...
shirbr510

2
सच। यह थ्रेड सुरक्षित नहीं है, कुछ थ्रेड पूल से विभिन्न थ्रेड्स का उपयोग किया जाएगा ... और मुझे अपने उत्तर को संशोधित करने की आवश्यकता है। जब मैं इसे आज़माता हूँ तो कोई ForEach () नहीं होता है .. जब मेरा इस के साथ विचार किया तो ForEach के साथ एक्सटेंशन वाला मेरा कोड होना चाहिए।
वोल्फ 5

6

ForEach का उद्देश्य साइड इफेक्ट्स पैदा करना है। IEnumerable एक सेट की आलसी गणना के लिए है।

जब आप इस पर विचार करते हैं तो यह वैचारिक अंतर काफी दिखाई देता है।

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

यह अभ्यस्त तब तक निष्पादित होता है जब तक आप "गणना" या "टोलिस्ट ()" या उस पर कुछ नहीं करते। यह स्पष्ट रूप से व्यक्त नहीं किया गया है।

आपको अपने संबंधित स्रोतों और शर्तों द्वारा निश्चित सामग्री, पुनरावृत्ति की श्रृंखला स्थापित करने के लिए IEnumerable एक्सटेंशन का उपयोग करना चाहिए। अभिव्यक्ति पेड़ शक्तिशाली और कुशल हैं, लेकिन आपको उनकी प्रकृति की सराहना करना सीखना चाहिए। और आलसी मूल्यांकन से अधिक कुछ पात्रों को बचाने के लिए उनके आसपास प्रोग्रामिंग के लिए नहीं।


5

कई लोगों ने इसका उल्लेख किया, लेकिन मुझे इसे लिखना पड़ा। क्या यह सबसे स्पष्ट / सबसे पठनीय नहीं है?

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

लघु और सरल (सेंट)।


आप पूरी पहली पंक्ति को छोड़ सकते हैं और सीधे Geteachems का उपयोग कर सकते हैं foreach
tymtam

3
बेशक। यह स्पष्टता के लिए इस तरह लिखा जाता है। ताकि यह स्पष्ट हो सके कि कौन सी GetItems()विधि वापस आती है।
नेनाद

4
अब जब मैंने अपनी टिप्पणी पढ़ी तो मुझे ऐसा लगा कि मैं आपको कुछ बता रहा हूँ जो आप नहीं जानते हैं। मेरा मतलब यह नहीं था। मेरा मतलब है कि foreach (var item in GetItems()) item.DoStuff();यह सिर्फ एक सौंदर्य है।
tymtam

4

अब हमारे पास विकल्प है ...

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

बेशक, यह थ्रेडवर्म की पूरी नई कैन को खोलता है।

ps (फोंट के बारे में क्षमा करें, यह सिस्टम ने तय किया है)


4

जैसा कि कई उत्तर पहले से ही इंगित करते हैं, आप आसानी से अपने आप में इस तरह की एक विस्तार विधि जोड़ सकते हैं। हालाँकि, यदि आप ऐसा नहीं करना चाहते हैं, हालाँकि मुझे BCL में ऐसा कुछ भी पता नहीं है, फिर भी Systemनाम स्थान में एक विकल्प है , यदि आपके पास पहले से ही प्रतिक्रियाशील विस्तार का संदर्भ है (और यदि आप नहीं करते हैं , आपको होना चाहिए):

using System.Reactive.Linq;

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

हालाँकि विधि के नाम थोड़े भिन्न हैं, अंतिम परिणाम वही है जो आप खोज रहे हैं।


ऐसा लगता है कि इस पैकेज को अब हटा दिया गया है
रेगेगिटेर

3

फॉरएच को भी जंजीर किया जा सकता है , बस कार्रवाई के बाद पायलट को वापस रख दिया जाए। धाराप्रवाह रहो


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();});

कार्यान्वयन का एक उत्सुक संस्करण।

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
}

संपादित करें: एक आलसी संस्करण उपज वापसी का उपयोग कर रहा है, इस तरह ।

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

आलसी संस्करण की आवश्यकता होती है भौतिक, ToList () उदाहरण के लिए, अन्यथा, कुछ भी नहीं होता है। टूलमेकरसेव के महान टिप्पणियों के नीचे देखें।

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

मैं अपनी लाइब्रेरी में ForEach () और ForEachLazy () दोनों रखता हूं।


2
क्या आपने इसका परीक्षण किया है? ऐसे कई संदर्भ हैं जहां यह विधि सहज रूप से गर्भनिरोधक का व्यवहार करती है। बेहतर होगाforeach(T item in enu) {action(item); yield return item;}
तैमूर

2
यह कई गणनाओं में परिणाम देगा
regisbsb

दिलचस्प। जब मैं 3 क्रियाओं के अनुक्रम के लिए ऊपर करना चाहूंगा, तो क्या करना है foreach (T item in enu) { action1(item); action2(item); action3(item); }? एक एकल, स्पष्ट, लूप। मुझे लगता है कि अगर एक्शन 2 को शुरू करना सभी एक्शन 1 से पहले करना महत्वपूर्ण था ।
टूलमेकरसैट

@ Rm558 - "उपज वापसी" का उपयोग करके आपका दृष्टिकोण। प्रो: केवल एक बार मूल अनुक्रम की गणना करता है, इसलिए व्यापक रूप से गणना के साथ सही ढंग से काम करता है। Con: यदि आप भूल जाते हैं ".ToArray ()" अंत में, कुछ नहीं होता है। हालांकि विफलता स्पष्ट होगी, लंबे समय तक नजरअंदाज नहीं किया जाएगा, इसलिए बड़ी लागत नहीं। मेरे लिए "साफ" महसूस नहीं करता है, लेकिन सही ट्रेडऑफ़ है, अगर कोई इस सड़क (एक फॉरेक्स ऑपरेटर) से नीचे जा रहा है।
टूलमेकरसैट

1
यह कोड लेन-देन के दृष्टिकोण से सुरक्षित नहीं है। यदि यह विफल हो जाए तो क्या होगा ProcessShipping()? आप खरीदार को ईमेल करते हैं, उसका क्रेडिट कार्ड चार्ज करते हैं, लेकिन कभी उसे अपना सामान नहीं भेजते हैं? निश्चित रूप से समस्याओं के लिए पूछ रहे हैं।
ज़मचेनिक

2

यह "कार्यात्मक दृष्टिकोण" अमूर्तता बड़ा समय लीक करता है। भाषा के स्तर पर कुछ भी दुष्प्रभाव को रोकता है। जब तक आप इसे कंटेनर में हर तत्व के लिए अपना लंबो / डेलीगेट कह सकते हैं - आपको "फॉरएच" व्यवहार मिलेगा।

यहाँ उदाहरण के लिए एक प्रकार से src retard को डिस्टर्बड में मर्ज करने का तरीका (यदि कुंजी पहले से मौजूद है - ओवरराइट्स)

यह एक हैक है, और इसका उपयोग किसी भी उत्पादन कोड में नहीं किया जाना चाहिए।

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

6
यदि आपको वह डिस्क्लेमर जोड़ना है, तो संभवतः आपको उसे पोस्ट नहीं करना चाहिए। एकदम मेरे विचार।
एंड्रयू ग्रोटे

2
यह कैसे से बेहतर है foreach(var tuple in srcDictionary) { destDictionary[tuple.Key] = tuple.Value; }? यदि उत्पादन कोड में नहीं है तो आपको इसका उपयोग कहां और क्यों करना चाहिए?
मार्क सॉलुल

3
यह सिर्फ दिखाने के लिए यह सिद्धांत में संभव है। यह वही होता है जो ओपी ने पूछा था, और मैंने स्पष्ट रूप से संकेत दिया था कि इसका उपयोग उत्पादन में नहीं किया जाना चाहिए, फिर भी उत्सुक हैं और शैक्षिक मूल्य हैं।
ज़ार शारदान

2

जॉन स्कीट से प्रेरित होकर, मैंने उसका समाधान निम्नलिखित के साथ बढ़ाया है:

विस्तार विधि:

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);
    }
}

ग्राहक:

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

मैं सम्मानपूर्वक इस धारणा से असहमत हूं कि लिंक विस्तार विधियाँ साइड-इफ़ेक्ट फ्री होनी चाहिए (न केवल इसलिए कि वे नहीं हैं, कोई भी प्रतिनिधि साइड इफेक्ट कर सकता है)।

निम्नलिखित को धयान मे रखते हुए:

   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);
      }
   }

उदाहरण से पता चलता है कि वास्तव में बस एक तरह का लेट-बाइंडिंग है जो तत्वों के अनुक्रम पर साइड-इफेक्ट वाले कई संभावित कार्यों में से एक को लागू करने की अनुमति देता है, बिना एक्शन को परिभाषित किए मूल्य को डिकोड करने के लिए एक बड़ा स्विच निर्माण लिखने के लिए और अनुवाद करने के लिए यह अपनी इसी विधि में है।


9
एक एक्सटेंशन विधि के साइड-इफ़ेक्ट हो सकते हैं या नहीं, इसके बीच अंतर है कि क्या यह होना चाहिए। आप केवल यह इंगित कर रहे हैं कि यह हो सकता है, जबकि यह प्रस्ताव करने के बहुत अच्छे कारण हो सकते हैं कि उनके दुष्प्रभाव नहीं होने चाहिए। फ़ंक्शनल प्रोग्रामिंग में, सभी फ़ंक्शंस साइड-इफ़ेक्ट फ़्री होते हैं, और फ़ंक्शनल प्रोग्रामिंग कंस्ट्रक्शंस का उपयोग करते समय आप यह मान सकते हैं कि वे हैं।
डेव वान डेन आइंडी

1

धाराप्रवाह रहने के लिए इस तरह की चाल का उपयोग किया जा सकता है:

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

0

VB.NET के लिए आपको उपयोग करना चाहिए:

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

नोट: यह केवल तभी संकलित करता है जब आपके पास Listया IList। एक सामान्य के लिए IEnumerable, स्वीकृत उत्तर फॉरबेक एक्सटेंशन विधि के बराबर VB लिखें ।
टूलमेकरसेव

-1

फिर भी एक और ForEachउदाहरण

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
स्मृति की बर्बादी क्या। यह ToList को एक सूची में जोड़ने के लिए कहता है। यह केवल पते क्यों नहीं लौटाता है। चयन करें (a => MapToDomain (a))
मार्क सॉलुल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.