IEnumerable पर कोई ForEach एक्सटेंशन विधि क्यों नहीं है?


389

गुम Zipसमारोह के बारे में पूछने वाले एक अन्य प्रश्न से प्रेरित :

कक्षा ForEachमें कोई विस्तार पद्धति क्यों नहीं है Enumerable? या कहीं भी? केवल वर्ग है कि एक हो जाता है ForEachतरीका है List<>। क्या कोई कारण है कि वह गायब है (प्रदर्शन)?


इसकी शायद पहले वाली पोस्ट से संकेत मिलता है, उस फ़ॉरचेक को C # और VB.NET (और कई अन्य) में एक भाषा कीवर्ड के रूप में समर्थित किया गया है, अधिकांश लोग (स्वयं शामिल) बस एक को खुद को आवश्यकतानुसार और उचित लिखते हैं।
क्रिस

2
संबंधित प्रश्न यहां answer आधिकारिक उत्तर ’के लिंक के साथ stackoverflow.com/questions/858978/…
बेंजोल

1
यह भी देखें stackoverflow.com/questions/200574/…
goodeye

मुझे लगता है कि एक बहुत महत्वपूर्ण बिंदु यह है कि एक फॉर्च लूप को स्पॉट करना आसान है। यदि आप .ForEach (...) का उपयोग करते हैं, तो इस एक को याद करना आसान है, जब आप कोड के माध्यम से देखते हैं। यह महत्वपूर्ण हो जाता है, जब आपके पास प्रदर्शन के मुद्दे होते हैं। बेशक .ToList () और .ToArray () में एक ही मुद्दा है, लेकिन उनका उपयोग थोड़ा अलग है। एक और कारण यह हो सकता है कि स्रोत सूची (फ़े रिमूविंग / एडिंग एलिमेंट्स) को संशोधित करने के लिए एक .ForEach में यह अधिक सामान्य है, इसलिए यह अब "शुद्ध" क्वेरी नहीं होगी।
डैनियल बिसार

समानांतर कोड डिबगिंग करते समय, मैं अक्सर केवल बाद वाले को फिर से दिखाने के Parallel.ForEachलिए स्वैपिंग का प्रयास करता हूं Enumerable.ForEach। सी # यहाँ चीजों को आसान बनाने के लिए एक चाल याद किया।
कर्नल पैनिक

जवाबों:


198

भाषा में पहले से ही शामिल एक फ़ार्च स्टेटमेंट है जो अधिकांश समय काम करता है।

मैं निम्नलिखित देखने से नफरत करता हूँ:

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

के बजाय:

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

उत्तरार्द्ध ज्यादातर स्थिति में स्पष्ट और आसान है , हालांकि टाइप करने के लिए शायद थोड़ा लंबा है।

हालाँकि, मुझे मानना ​​होगा कि मैंने उस मुद्दे पर अपना रुख बदल दिया है; फॉरएच () एक्सटेंशन विधि वास्तव में कुछ स्थितियों में उपयोगी होगी।

कथन और विधि के बीच मुख्य अंतर इस प्रकार हैं:

  • प्रकार की जाँच: फ़ोरच रनटाइम पर किया जाता है, ForEach () संकलन समय (बिग प्लस!) पर है
  • एक प्रतिनिधि को कॉल करने के लिए वाक्यविन्यास वास्तव में बहुत सरल है: ऑब्जेक्ट्स। फ़ोरएच (DoSomething);
  • ForEach () जंजीर हो सकता है: हालांकि इस तरह की सुविधा की बुराई / उपयोगिता चर्चा के लिए खुली है।

वे सभी बहुत से लोगों द्वारा यहां बनाए गए बिंदु हैं और मैं देख सकता हूं कि लोग फ़ंक्शन को क्यों याद कर रहे हैं। मुझे बुरा नहीं लगेगा कि Microsoft अगली फ्रेमवर्क पुनरावृत्ति में एक मानक ForEach विधि जोड़ रहा है।


39
यहाँ चर्चा इसका जवाब देती है: forum.microsoft.com/MSDN/… मूल रूप से विस्तार के तरीकों को "शुद्ध" रखने के लिए निर्णय लिया गया था। एक ForEach विस्तार के तरीकों का उपयोग करते समय दुष्प्रभावों को प्रोत्साहित करेगा, जो कि इरादा नहीं था।
प्रातः

17
यदि आपके पास C बैकग्राउंड है, तो 'foreach' स्पष्ट लग सकता है, लेकिन आंतरिक पुनरावृत्ति आपके इरादे को स्पष्ट रूप से बताता है। इसका मतलब है कि आप 'अनुक्रम.ए.एसपैरल ()। फॉरइच (...)' जैसी चीजें कर सकते हैं।
जे। बज़ुज़ी

10
मुझे यकीन नहीं है कि जाँच के बारे में आपकी बात सही है। foreachयदि कंप्यूमर को पैरामीटर किया गया है, तो संकलन समय पर टाइप किया जाता है। यह केवल गैर-सामान्य संग्रहों के संकलन समय की जाँच का अभाव है, जैसा कि एक काल्पनिक ForEachविस्तार विधि होगी।
रिचर्ड पोले

49
विस्तार विधि श्रृंखला LINQ में डॉट नोटेशन के साथ वास्तव में उपयोगी होगी, जैसे col.Where(...).OrderBy(...).ForEach(...):। बहुत सरल सिंटैक्स, कोई स्क्रीन प्रदूषण या तो निरर्थक स्थानीय चर या फॉर्च्यूनर () में लंबे ब्रैकेट्स के साथ नहीं।
जसक गोर्गो

22
"मैं निम्नलिखित देखने से नफरत करूंगा" - सवाल आपकी व्यक्तिगत प्राथमिकताओं के बारे में नहीं था, और आपने बाहरी लाइनफीड्स और एक बाहरी जोड़ी ब्रेसिज़ को जोड़कर कोड को अधिक घृणित बना दिया। इतनी नफरत नहीं है list.ForEach(item => item.DoSomething())। और कौन कहता है कि यह एक सूची है? स्पष्ट उपयोग मामला एक श्रृंखला के अंत में है; फॉरचेट स्टेटमेंट के साथ, आपको पूरी श्रृंखला के बाद in, और ब्लॉक के अंदर प्रदर्शन करने के लिए ऑपरेशन करना होगा, जो बहुत कम प्राकृतिक या सुसंगत है।
जिम बैटर

73

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

हालांकि, यदि आप वास्तव में इस छोटे से समारोह को याद करते हैं, तो आप अपने स्वयं के संस्करण को रोल आउट कर सकते हैं

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

11
विस्तार विधियाँ इसके लिए अनुमति देती हैं। यदि पहले से ही किसी दिए गए विधि नाम का एक उदाहरण कार्यान्वयन है, तो उस पद्धति का उपयोग एक्सटेंशन विधि के बजाय किया जाता है। तो आप एक विस्तार विधि लागू कर सकते हैं ForEach और नहीं यह सूची के साथ टकराता है <> ForEach विधि।
कैमरन मैकफारलैंड

3
कैमरन, मुझे विश्वास है कि मुझे पता है कि विस्तार के तरीके कैसे काम करते हैं :) सूची IEnumerable विरासत में मिलती है इसलिए यह गैर-स्पष्ट बात होगी।
एक्यू

9
एक्सटेंशन मेथड्स प्रोग्रामिंग गाइड ( msdn.microsoft.com/en-us/library/bb383977.aspx ) से: एक इंटरफ़ेस और क्लास विधि के रूप में एक ही नाम और हस्ताक्षर के साथ एक विस्तार विधि कभी नहीं कहा जाएगा। मेरे लिए बहुत स्पष्ट लगता है।
कैमरून मैकफारलैंड

3
क्या मैं कुछ अलग बात कर रहा हूँ? मुझे लगता है कि यह अच्छा नहीं है जब कई वर्गों के पास फॉरच विधि है, लेकिन उनमें से कुछ अलग तरीके से काम कर सकते हैं।
एक्यू

5
सूची <> के बारे में ध्यान देने वाली एक दिलचस्प बात। ForEach और Array.ForEach यह है कि वे वास्तव में आंतरिक रूप से foreach का उपयोग नहीं कर रहे हैं। वे दोनों लूप के लिए एक मैदान का उपयोग करते हैं। शायद यह एक प्रदर्शन की बात है ( diditwith.net/2006/10/05/PerformanceOfForeachVsListForEach.aspx )। लेकिन यह देखते हुए कि, Array और List दोनों ही ForEach Methods को कार्यान्वित करते हैं, यह आश्चर्यजनक है कि वे कम से कम IList <> के लिए एक्सटेंशन विधि लागू नहीं करते हैं, यदि IEnumerable <> के लिए भी नहीं।
मैट डॉटसन

53

आप यह एक्सटेंशन विधि लिख सकते हैं:

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

पेशेवरों

चैनिंग की अनुमति देता है:

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

विपक्ष

यह वास्तव में कुछ भी नहीं करेगा जब तक आप पुनरावृत्ति के लिए कुछ करने के लिए नहीं करते हैं। उस कारण से, इसे नहीं बुलाया जाना चाहिए .ForEach()। आप .ToList()अंत में लिख सकते हैं , या आप इस विस्तार विधि को भी लिख सकते हैं:

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

    return source;
}

यह शिपिंग सी # लाइब्रेरी से बहुत महत्वपूर्ण हो सकता है; जो पाठक आपके एक्सटेंशन के तरीकों से परिचित नहीं हैं, वे नहीं जान पाएंगे कि आपका कोड क्या है।


1
यदि आपका पहला कार्य w / आउट का उपयोग किया जा सकता है, तो यदि यह लिखा हो:{foreach (var e in source) {action(e);} return source;}
jjnguy

3
क्या आप अपनी लागू पद्धति के बजाय सिर्फ चयन का उपयोग नहीं कर सकते थे? यह मुझे लगता है कि प्रत्येक तत्व के लिए एक क्रिया को लागू करना और इसे चुनना ठीक वही है जो चयन करता है। जैसेnumbers.Select(n => n*2);
रासुमशवसेन २३'१३ को v

1
मुझे लगता है कि इस उद्देश्य के लिए Select का उपयोग करने की तुलना में Apply अधिक पठनीय है। सेलेक्ट स्टेटमेंट पढ़ते समय, मैंने इसे "इनसाइड से कुछ प्राप्त करें" के रूप में पढ़ा, जहां अप्लाई "कुछ काम करें" है।
डॉ। रॉब लैंग

2
@rasmusvhansen वास्तव में, Select()प्रत्येक तत्व के लिए एक फ़ंक्शन लागू करने और फ़ंक्शन का मान वापस करने के लिए Apply()कहता है जहां Actionप्रत्येक तत्व पर लागू होता है और मूल तत्व वापस करता है।
नेटमैज

1
यह इसके बराबर हैSelect(e => { action(e); return e; })
जिम बाल्टर

35

यहाँ चर्चा इसका जवाब देती है:

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

मूल रूप से विस्तार के तरीकों को कार्यात्मक रूप से "शुद्ध" रखने का निर्णय लिया गया था। एक ForEach Enumerable एक्सटेंशन विधियों का उपयोग करते समय साइड-इफेक्ट्स को प्रोत्साहित करेगा, जो कि इरादा नहीं था।


6
Blogs.msdn.com/b/ericlippert/archive/2009/05/18/… भी देखें । Ddoing इतना कार्यात्मक प्रोग्रामिंग सिद्धांतों का उल्लंघन करता है कि अन्य सभी अनुक्रम ऑपरेटर पर आधारित हैं। स्पष्ट रूप से इस पद्धति के लिए एक कॉल का एकमात्र उद्देश्य साइड इफेक्ट्स का कारण है
माइकल फ्रीजिम

7
वह तर्क पूरी तरह से संगीन है। उपयोग के मामले कि दुष्प्रभाव की जरूरत है ... foreach के बिना, आप एक foreach पाश लिखने के लिए है। ForEach का अस्तित्व दुष्प्रभावों को प्रोत्साहित नहीं करता है और इसकी अनुपस्थिति उन्हें कम नहीं करती है।
जिम बाल्टर

यह देखते हुए कि विस्तार विधि लिखना कितना सरल है, इसका शाब्दिक कोई कारण नहीं है कि यह भाषा मानक नहीं है।
कप्तान प्रिंसी

17

हालांकि मैं मानता हूं कि foreachज्यादातर मामलों में अंतर्निहित निर्माण का उपयोग करना बेहतर है , मुझे इस बदलाव का उपयोग फॉरएच <> के विस्तार से मिलता है, जो कि नियमित रूप से foreachखुद को सूचकांक का प्रबंधन करने की तुलना में थोड़ा अच्छा है।

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;
}
उदाहरण
var people = new[] { "Moe", "Curly", "Larry" };
people.ForEach((i, p) => Console.WriteLine("Person #{0} is {1}", i, p));

आपको देंगे:

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

महान विस्तार, लेकिन क्या आप कुछ प्रलेखन जोड़ सकते हैं? लौटाए गए मूल्य का इच्छित उपयोग क्या है? विशेष रूप से इंट के बजाय इंडेक्स संस्करण क्यों है? नमूना उपयोग?
मार्क टी

मार्क: रिटर्न मान सूची में तत्वों की संख्या है। इंडेक्स को विशेष रूप से एक इंट के रूप में टाइप किया जाता है, जिसका मतलब निहित टाइपिंग है।
क्रिस Zwiryk

@ क्रिस, ऊपर आपके कोड के आधार पर, वापसी मूल्य सूची में अंतिम मूल्य का शून्य-आधारित सूचकांक है, सूची में तत्वों की संख्या नहीं।
एरिक स्मिथ

@ क्रिस, नहीं, यह नहीं है: मूल्य बढ़ने के बाद सूचकांक में वृद्धि हुई है (पोस्टफिक्स वेतन वृद्धि), इसलिए पहले तत्व को संसाधित करने के बाद, सूचकांक 1 और इसी तरह होगा। इसलिए रिटर्न वैल्यू वास्तव में एलिमेंट काउंट है।
मार्टिनस्टैटनर

1
@MartinStettner 5/16 पर एरिक स्मिथ की टिप्पणी एक पुराने संस्करण से थी। उन्होंने सही मान लौटाने के लिए 5/18 पर कोड को सही किया।
माइकल ब्लैकबर्न

16

एक वर्कअराउंड लिखना है .ToList().ForEach(x => ...)

पेशेवरों

समझने में आसान - पाठक को केवल यह जानने की जरूरत है कि सी # के साथ कौन से जहाज हैं, कोई अतिरिक्त विस्तार के तरीके नहीं।

सिंथेटिक शोर बहुत हल्का होता है (केवल थोड़ा अतिरिक्त कोड जोड़ता है)।

आमतौर पर अतिरिक्त मेमोरी का खर्च नहीं होता है, क्योंकि किसी मूल निवासी .ForEach()को वैसे भी पूरे संग्रह का एहसास करना होगा।

विपक्ष

संचालन का क्रम आदर्श नहीं है। मुझे इसके बजाय एक तत्व का एहसास होता है, फिर उस पर कार्रवाई करते हैं, फिर दोहराते हैं। यह कोड पहले सभी तत्वों को महसूस करता है, फिर प्रत्येक क्रम में उन पर कार्य करता है।

यदि सूची को साकार करने के लिए एक अपवाद फेंकता है, तो आपको कभी भी एक तत्व पर कार्रवाई करने की आवश्यकता नहीं है।

यदि गणना अनंत है (प्राकृतिक संख्याओं की तरह), तो आप भाग्य से बाहर हैं।


1
a) यह प्रश्न का उत्तर दूरस्थ रूप से भी नहीं है। ख) यह प्रतिक्रिया स्पष्ट होगी यदि यह सामने उल्लेख किया है कि, जबकि कोई Enumerable.ForEach<T>विधि नहीं है, एक List<T>.ForEachविधि है। ग) "आम तौर पर अतिरिक्त मेमोरी का खर्च नहीं होता है, क्योंकि एक देशी .ForEach () को वैसे भी पूरे संग्रह का एहसास करना होगा।" - पूर्ण और नितांत बकवास। यहाँ Enumerable.ForEach का कार्यान्वयन है <T> कि C # प्रदान करता है अगर यह किया है:public static void ForEach<T>(this IEnumerable<T> list, Action<T> action) { foreach (T item in list) action(item); }
जिम Balter

13

मुझे हमेशा आश्चर्य होता है कि मैं खुद यही हूं, इसलिए मैं हमेशा इसे अपने साथ रखता हूं:

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

अच्छा सा विस्तार विधि।


2
कर्नल अशक्त हो सकता है ... आप यह भी देख सकते हैं।
एमी बी

हाँ, मैं अपनी लाइब्रेरी में जाँच करता हूँ, मैंने इसे जल्दी से वहाँ करते समय याद किया।
एरोन पॉवेल

मुझे यह दिलचस्प लगता है कि हर कोई अशक्त के लिए कार्रवाई पैरामीटर की जांच करता है, लेकिन स्रोत / कॉल पैरामीटर कभी नहीं।
कैमरून मैकफारलैंड

2
मुझे यह दिलचस्प लगता है कि हर कोई अशक्त के लिए मापदंडों की जांच करता है, जब एक अपवाद के रूप में अच्छी तरह से परिणाम की जांच नहीं करता है ...
o

हर्गिज नहीं। एक नल रेफरी अपवाद आपको उस पैरामीटर का नाम नहीं बताएगा जो गलती पर था। और आप लूप में भी जांच कर सकते हैं ताकि आप एक विशिष्ट नल रेफरी फेंक सकें कह सकते हैं कि कर्नल [सूचकांक #] एक ही कारण से अशक्त था
रोजर विलकॉक्स

8

इसलिए इस तथ्य के बारे में बहुत सी टिप्पणियां की गई हैं कि एक ForEach एक्सटेंशन विधि उचित नहीं है क्योंकि यह LINQ एक्सटेंशन विधियों की तरह कोई मान नहीं लौटाता है। हालांकि यह एक तथ्यात्मक कथन है, यह पूरी तरह सच नहीं है।

LINQ एक्सटेंशन मेथड्स सभी एक वैल्यू लौटाते हैं ताकि उन्हें एक साथ चैन किया जा सके:

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

हालांकि, सिर्फ इसलिए कि LINQ को कार्यान्वित किया जाता है एक्सटेंशन विधियों का उपयोग करने का मतलब यह नहीं है कि एक्सटेंशन विधियों का उपयोग उसी तरीके से किया जाना चाहिए और मान वापस करना चाहिए। सामान्य कार्यक्षमता को उजागर करने के लिए एक विस्तार विधि लिखना जो एक मान नहीं लौटाता है एक पूरी तरह से वैध उपयोग है।

ForEach के बारे में विशिष्ट तर्क यह है कि विस्तार विधियों पर बाधाओं के आधार पर (अर्थात कि एक विस्तार विधि एक ही हस्ताक्षर के साथ विरासत में मिली विधि को कभी भी ओवरराइड नहीं करेगी ), ऐसी स्थिति हो सकती है जहां सभी वर्गों पर कस्टम एक्सटेंशन पद्धति उपलब्ध हो - प्रतिरूपण IEnumerable > सूची को छोड़कर >। यह भ्रम पैदा कर सकता है जब विस्तार विधि या विरासत विधि कहा जा रहा है या नहीं इसके आधार पर तरीके अलग-अलग व्यवहार करना शुरू करते हैं।<T<T


7

आप (चेनेबल, लेकिन आलसी मूल्यांकन) का उपयोग कर सकते हैं Select, पहले अपना ऑपरेशन कर रहे हैं, और फिर पहचान वापस कर रहे हैं (या आपके द्वारा कुछ और)

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

आपको यह सुनिश्चित करने की आवश्यकता होगी कि यह अभी भी मूल्यांकन किया गया है, या तो Count()(सबसे सस्ता ऑपरेशन एन्यूमरेट करने के लिए) या किसी अन्य ऑपरेशन की वैसे भी आपको आवश्यकता है।

मैं इसे मानक पुस्तकालय में लाया देखना पसंद करूंगा, हालांकि:

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

उपरोक्त कोड तब people.WithLazySideEffect(p => Console.WriteLine(p))प्रभावी हो जाता है जो प्रभावी रूप से फॉर्च के बराबर होता है, लेकिन आलसी और चेन योग्य।


शानदार, यह कभी नहीं क्लिक करता है कि एक लौटा हुआ चयन इस तरह से काम करेगा। विधि सिंटैक्स का एक अच्छा उपयोग, जैसा कि मुझे नहीं लगता कि आप अभिव्यक्ति सिंटैक्स के साथ ऐसा कर सकते हैं (इसलिए मैंने पहले कभी ऐसा नहीं सोचा है)।
एलेक्स कीस्मिथ

@AlexKeySmith आप इसे अभिव्यक्ति सिंटैक्स के साथ कर सकते हैं यदि C # में एक अनुक्रम ऑपरेटर होता है, जैसे कि इसका पूर्वाभास। लेकिन ForEach की पूरी बात यह है कि यह शून्य प्रकार के साथ एक कार्रवाई करता है, और आप C # में अभिव्यक्तियों में शून्य प्रकार का उपयोग नहीं कर सकते।
जिम बाल्टर

imho, अब Selectवह नहीं करता है जो वह करने वाला है। यह निश्चित रूप से एक समाधान है जो ओपी पूछता है - लेकिन विषय पठनीयता पर: कोई भी उम्मीद नहीं करेगा कि चयन एक फ़ंक्शन को निष्पादित करता है।
मथायस बर्गर

@MatthiasBurger यदि Selectऐसा नहीं किया जाता है, तो इसे लागू करने में समस्या होती है Select, न कि उस कोड के साथ जो कॉल करता है Select, जिस पर कोई प्रभाव नहीं पड़ता Selectहै।
मार्टिज़न

5

ध्यान दें कि MoreLINQ NuGet आपके द्वारा ढूंढी जा रही ForEachएक्सटेंशन विधि प्रदान करता है (साथ ही एक Pipeविधि जो प्रतिनिधि को निष्पादित करता है और उसका परिणाम देता है)। देख:


4

@Coincoin

फ़ॉरेस्ट एक्सटेंशन विधि की वास्तविक शक्ति में Action<>आपके कोड में अनावश्यक तरीकों को जोड़े बिना पुन: प्रयोज्य शामिल है । यह कहें कि आपके पास 10 सूचियां हैं और आप उन पर एक ही तर्क करना चाहते हैं, और एक संबंधित कार्य आपकी कक्षा में फिट नहीं होता है और इसका पुन: उपयोग नहीं किया जाता है। लूप्स के लिए दस होने के बजाय, या एक सामान्य फ़ंक्शन जो स्पष्ट रूप से सहायक नहीं है, आप अपने सभी तर्क को एक स्थान पर रख सकते हैं ( Action<>इसलिए, दर्जनों लाइनों को बदल दिया जाता है।

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

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

आदि...

तर्क एक जगह पर है और आपने अपनी कक्षा को प्रदूषित नहीं किया है।


foreach (List1.Concat (List2) (.Concat (List3)) {... do stuff ...}
कैमरन मैकफारलैंड

यदि यह उतना ही सरल है f(p), तो { }आशुलिपि के लिए बाहर निकलें for (var p in List1.Concat(List2).Concat(List2)) f(p);:।
स्पूलसन

3

LINQ एक्सटेंशन विधियों में से अधिकांश परिणाम लौटाते हैं। फॉरएच इस पैटर्न में फिट नहीं है क्योंकि यह कुछ भी नहीं लौटाता है।


2
फॉरएच एक्शन <टी> का उपयोग करता है, जो प्रतिनिधि का दूसरा रूप है
आरोन पॉवेल

2
लीपी के अधिकार को छोड़कर, सभी Enumerable एक्सटेंशन विधियों का एक मान लौटता है, इसलिए ForEach पैटर्न फिट नहीं होता है। प्रतिनिधि इसमें नहीं आते हैं।
कैमरन मैकफारलैंड

बस एक विस्तार विधि का परिणाम वापस नहीं करना है, यह एक बार-बार उपयोग किए जाने वाले ऑपरेशन को कॉल करने के तरीके को जोड़ने के उद्देश्य से कार्य करता है
आरोन पॉवेल

1
दरअसल, स्लूस। तो क्या हुआ अगर यह एक मूल्य वापस नहीं करता है?
ट्रॉमापॉनी

1
@Martijn यानीpublic IEnumerable<T> Foreach<T>(this IEnumerable<T> items, Action<T> action) { /* error check */ foreach (var item in items) { action(item); yield return item; } }
मैके

3

यदि आपके पास F # (जो .NET के अगले संस्करण में होगा), आप उपयोग कर सकते हैं

Seq.iter doSomething myIEnumerable


9
इसलिए Microsoft ने C # और VB में IEnumerable के लिए ForEach विधि प्रदान करने का विकल्प नहीं चुना, क्योंकि यह शुद्ध रूप से कार्यात्मक नहीं होगा; अभी तक वे अपनी अधिक कार्यात्मक भाषा F # में इसे (नाम iter) प्रदान करते हैं। उनका तर्क मुझे भाता है।
स्कॉट हचिंसन

3

आंशिक रूप से यह इसलिए है क्योंकि भाषा डिजाइनर दार्शनिक दृष्टिकोण से इससे असहमत हैं।

  • नहीं (और परीक्षण ...) एक सुविधा होने से कम काम है।
  • यह वास्तव में कम नहीं है (कुछ पासिंग फंक्शन के मामले हैं जहां यह है, लेकिन यह प्राथमिक उपयोग नहीं होगा)।
  • इसका उद्देश्य साइड इफेक्ट्स होना है, जो कि लिनक के बारे में नहीं है।
  • हमारे पास पहले से मिली एक सुविधा के रूप में एक ही काम करने का एक और तरीका क्यों है? (फॉरवर्ड कीवर्ड)

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


2

जब आप कुछ वापस करना चाहते हैं तो आप चुनिंदा का उपयोग कर सकते हैं। यदि आप नहीं करते हैं, तो आप पहले ToList का उपयोग कर सकते हैं, क्योंकि आप शायद संग्रह में कुछ भी संशोधित नहीं करना चाहते हैं।


a) यह प्रश्न का उत्तर नहीं है। b) ToList को अतिरिक्त समय और मेमोरी की आवश्यकता होती है।
जिम बैटर

2

मैंने इसके बारे में एक ब्लॉग पोस्ट लिखा: http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/forn.xx

यदि आप .NET 4.0 में इस पद्धति को देखना चाहते हैं तो आप यहां वोट कर सकते हैं: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=279093


क्या इसे कभी लागू किया गया था? मैं कल्पना नहीं करता, लेकिन क्या कोई अन्य URL है जो उस टिकट को बदलता है? MS कनेक्ट बंद कर दिया गया है
knocte

यह लागू नहीं किया गया था। एक नई समस्या के दर्ज करने पर विचार github.com/dotnet/runtime/issues
किरिल Osenkov

2

3.5 में, IEnumerable में जोड़े गए सभी एक्सटेंशन तरीके LINQ समर्थन के लिए हैं (ध्यान दें कि वे System.Linq.Enumerable वर्ग में परिभाषित हैं)। इस पोस्ट में, मैं समझाता हूँ कि foreach LINQ में क्यों नहीं है: Parallel.For के समान मौजूदा LINQ एक्सटेंशन विधि?


2

क्या यह मुझे या लिस्ट <T> है। बहुत अधिक लाइनक द्वारा अप्रचलित कर दिया गया है। मूल रूप से था

foreach(X x in Y) 

जहां Y को बस IEnumerable होना चाहिए (Pre 2.0), और एक GetEnumerator () लागू करें। यदि आप उत्पन्न MSIL को देखते हैं तो आप देख सकते हैं कि यह बिल्कुल वैसा ही है

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

    Console.WriteLine(i);
}

( MSIL के लिए http://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspx देखें )

फिर DotNet2.0 जेनरिक में और सूची के साथ आया। फॉरच ने हमेशा मुझे विस्टर पैटर्न के कार्यान्वयन के लिए महसूस किया है, (गामा, हेल्म, जॉनसन, व्लाइसीड्स द्वारा डिज़ाइन पैटर्न देखें)।

अब 3.5 में निश्चित रूप से हम एक ही प्रभाव के लिए एक लैम्बडा का उपयोग कर सकते हैं, उदाहरण के लिए http://dotnet-developments.blogs.techtarget.com/2008/09/02/iterators-lambda-and-linq-oh- देखें मेरे/


1
मेरा मानना ​​है कि "foreach" के लिए जनरेट किए गए कोड में एक कोशिश अंत में होनी चाहिए। क्योंकि T का IEnumerator इंटरफ़ेस IDisposable से विरासत में मिला है। तो, उत्पन्न अंत में ब्लॉक में, टी उदाहरण के IEnumerator को विच्छेदित किया जाना चाहिए।
मॉर्गन चेंग

2

मैं अकु के उत्तर पर विस्तार करना चाहूंगा ।

यदि आप पूरी तरह से पूरी तरह से पुनरावृत्ति किए बिना इसके दुष्प्रभाव के एकमात्र उद्देश्य के लिए एक विधि को कॉल करना चाहते हैं, तो आप इसका उपयोग कर सकते हैं:

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

1
यह उसी तरह हैSelect(x => { f(x); return x;})
जिम बेल्टर

0

किसी ने अभी तक यह नहीं बताया है कि ForEach <T> परिणाम संकलन समय प्रकार की जाँच कर रहा है जहाँ foreach कीवर्ड रनटाइम चेक किया गया है।

कुछ रीफैक्टरिंग करने के बाद, जहां दोनों विधियों का उपयोग कोड में किया गया था, मैं एहसान करता हूं। जैसे कि, मुझे फेलियर समस्याओं का पता लगाने के लिए परीक्षण विफलताओं / रनटाइम विफलताओं का शिकार करना पड़ा।


5
क्या वास्तव में यह मामला है? मैं यह देखने में विफल हूं कि foreachकिसी भी कम समय संकलन की जांच कैसे की जाती है। यकीन है, अगर आपका संग्रह एक गैर-सामान्य IEnumerable है, तो लूप चर एक होगा object, लेकिन एक काल्पनिक ForEachविस्तार विधि के लिए भी यही सच होगा ।
रिचर्ड पोले

1
उल्लिखित उत्तर में इसका उल्लेख है। हालाँकि, यह केवल गलत है (और ऊपर रिचर्ड पॉले सही है)।
जिम बैटर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.