इस चेतावनी के दो भाग हैं। पहला है ...
क्लोजर में फॉर्च्यूनर चर तक पहुंच
... जो प्रति अवैध नहीं है, लेकिन यह पहली नज़र में प्रति-सहज है। सही करना बहुत कठिन है। (इतना कि लेख मैं नीचे लिंक करने के लिए यह "हानिकारक" के रूप में वर्णन करता है।)
अपनी क्वेरी लें, यह ध्यान रखें कि आपके द्वारा कोड किया गया कोड मूल रूप से C # संकलक (C # 5 से पहले) का एक विस्तारित रूप है जो foreach1 के लिए उत्पन्न होता है :
मुझे समझ में नहीं आता कि क्यों [निम्नलिखित है] वैध नहीं है:
string s; while (enumerator.MoveNext()) { s = enumerator.Current; ...
खैर, यह वाक्यात्मक रूप से मान्य है। और यह सब आप अपने पाश में कर रहे हैं उपयोग कर रहा है, तो मूल्य की sतो सब कुछ अच्छा है। लेकिन ओवर sक्लोज करने से काउंटर-सहज व्यवहार होगा। निम्नलिखित कोड पर एक नज़र डालें:
var countingActions = new List<Action>();
var numbers = from n in Enumerable.Range(1, 5)
select n.ToString(CultureInfo.InvariantCulture);
using (var enumerator = numbers.GetEnumerator())
{
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
Console.WriteLine("Creating an action where s == {0}", s);
Action action = () => Console.WriteLine("s == {0}", s);
countingActions.Add(action);
}
}
यदि आप यह कोड चलाते हैं, तो आपको निम्न कंसोल आउटपुट मिलेगा:
Creating an action where s == 1
Creating an action where s == 2
Creating an action where s == 3
Creating an action where s == 4
Creating an action where s == 5
आपसे यही उम्मीद है।
कुछ ऐसी चीज़ों को देखने के लिए, जिनकी आप संभवतः अपेक्षा नहीं करते हैं, उपरोक्त कोड के तुरंत बाद निम्नलिखित कोड चलाएँ :
foreach (var action in countingActions)
action();
आपको निम्न कंसोल आउटपुट मिलेगा:
s == 5
s == 5
s == 5
s == 5
s == 5
क्यों? क्योंकि हमने पाँच कार्य किए हैं जो सभी एक ही कार्य करते हैं: s(जो हमने बंद कर दिया है) का मान मुद्रित करें । वास्तव में, वे एक ही कार्य कर रहे हैं ("प्रिंट s", "प्रिंट s", "प्रिंट s" ...)।
जिस बिंदु पर हम उनका उपयोग करने के लिए जाते हैं, वे वही करते हैं जो हम पूछते हैं: के मूल्य को प्रिंट करें s। यदि आप अंतिम ज्ञात मूल्य को sदेखते हैं, तो आप देखेंगे कि यह है 5। इसलिए हम s == 5पांच बार कंसोल में प्रिंट होते हैं।
जो ठीक वैसा ही है जैसा हमने मांगा था, लेकिन शायद वह नहीं जो हम चाहते हैं।
चेतावनी का दूसरा भाग ...
संकलक के विभिन्न संस्करणों के साथ संकलित होने पर अलग व्यवहार हो सकता है।
... यह क्या है। C # 5 से शुरू होकर, कंपाइलर अलग कोड बनाता है जो इसे होने से रोकता हैforeach ।
इस प्रकार निम्नलिखित कोड संकलक के विभिन्न संस्करणों के तहत अलग-अलग परिणाम देगा:
foreach (var n in numbers)
{
Action action = () => Console.WriteLine("n == {0}", n);
countingActions.Add(action);
}
नतीजतन, यह R # चेतावनी भी उत्पन्न करेगा :)
मेरा पहला कोड स्निपेट, ऊपर, संकलक के सभी संस्करणों में समान व्यवहार प्रदर्शित करेगा, क्योंकि मैं उपयोग नहीं कर रहा हूं foreach(बल्कि, मैंने इसे पूर्व-सी # 5 संकलक करने के तरीके का विस्तार किया है)।
क्या यह सीएलआर संस्करण के लिए है?
मुझे पूरा यकीन नहीं है कि आप यहां क्या पूछ रहे हैं।
एरिक लिपर्ट के पोस्ट में कहा गया है कि परिवर्तन "C # 5" में होता है। इसलिएसंभवतः आपको .NET 4.5 या उसके बाद का लक्ष्य बनाना होगा नए व्यवहार को प्राप्त करने के लिए C # 5 या बाद के संकलक के साथ, और इससे पहले की सब कुछ पुराने व्यवहार को प्राप्त करता है।
लेकिन स्पष्ट होने के लिए, यह संकलक का कार्य है न कि .NET फ्रेमवर्क संस्करण।
क्या आईएल के साथ प्रासंगिकता है?
अलग-अलग कोड अलग-अलग IL का निर्माण करता है, इस लिहाज से IL के लिए परिणाम उत्पन्न होते हैं।
1 foreach आपकी टिप्पणी में पोस्ट किए गए कोड की तुलना में बहुत अधिक सामान्य निर्माण है। समस्या आमतौर पर foreachमैनुअल एन्यूमरेशन के माध्यम से नहीं, के उपयोग के माध्यम से उत्पन्न होती है । इसीलिए foreachC # 5 में बदलाव इस मुद्दे को रोकने में मदद करते हैं, लेकिन पूरी तरह से नहीं।