2015-07-23 15 views

उत्तर

40

List<T>.GetEnumerator() एक परिवर्तनशील मान प्रकार (List<T>.Enumerator) देता है। आप अज्ञात प्रकार में उस मान को संग्रहीत कर रहे हैं।

while (x.TempList.MoveNext()) 
{ 
    // Ignore this 
} 

कि बराबर है करने के लिए:: - मूल्य का प्रतिलिपि

while (true) 
{ 
    var tmp = x.TempList; 
    var result = tmp.MoveNext(); 
    if (!result) 
    { 
     break; 
    } 

    // Original loop body 
} 

अब ध्यान दें कि हम क्या पर MoveNext() कॉल कर रहे हैं

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

आप के लिए कोड को बदलते हैं:

var x = new { TempList = (IEnumerable<int>) new List<int> { 1, 3, 6, 9 }.GetEnumerator() }; 

... तो आप गुमनाम प्रकार में एक संदर्भ हो रही समाप्त कर देंगे। म्यूटेबल वैल्यू वाले बॉक्स का संदर्भ। जब आप उस संदर्भ पर MoveNext() पर कॉल करते हैं, तो बॉक्स के अंदर का मान उत्परिवर्तित हो जाएगा, इसलिए यह वही करेगा जो आप चाहते हैं।

एक समान स्थिति पर विश्लेषण के लिए (फिर List<T>.GetEnumerator() का उपयोग करके) my 2010 blog post "Iterate, damn you!" देखें।

+3

मैं इसे देख रहा हूं और यह पता लगाने में परेशानी है कि यहां कौन सा तत्व एक मूल्य प्रकार है जिसके लिए प्रतिलिपि/संदर्भ भेद वास्तव में एक फर्क पड़ता है। –

+1

मुझे यह नहीं मिला, यह ठीक काम करता है अगर हम इसे '' numerumerable ''?? @ जोनस्केट आप इसे सरल शब्दों में अधिक समझा सकते हैं –

+1

@ एहसान सजद: जब 'टेम्पललिस्ट' का संकलन-समय प्रकार 'आईनेमेरेबल ' है, तो इसका उपयोग केवल एक संदर्भ की प्रतिलिपि बनाता है। उस संदर्भ पर कार्य करने से बॉक्स किए गए मान को म्यूटेट कर दिया जाएगा, और अगली बार जब आप कोई संदर्भ कॉपी करेंगे तो यह अभी भी उसी बॉक्स किए गए मान को संदर्भित करेगा, इसलिए आप परिवर्तन देखेंगे। उस मूल्य की प्रतिलिपि बनाने और उस प्रति को म्यूट करने के साथ तुलना करें - जब आप * अगली * मूल मान की प्रतिलिपि बनाते हैं, तो आपको पिछले परिवर्तन दिखाई नहीं देंगे। –

3

VB.NET में सी # में foreach निर्माण और For Each पाश अक्सर प्रकार है कि IEnumerable<T> लागू के साथ किया जाता है, वे किसी भी प्रकार जो एक GetEnumerator विधि जिसका वापसी प्रकार एक उपयुक्त MoveNext समारोह और Current संपत्ति प्रदान करता है शामिल हैं को स्वीकार करेंगे। GetEnumeratorforeach को IEnumerator<T> लौटाए जाने के मुकाबले अधिक कुशलता से कार्यान्वित करने के लिए foreach को एक मूल्य प्रकार वापस करने की अनुमति दें।

दुर्भाग्य से, क्योंकि वहाँ कोई साधन है जिसके द्वारा एक प्रकार एक मूल्य के प्रकार प्रगणक जब भी एक की आपूर्ति जब एक GetEnumerator विधि कॉल द्वारा लाया बिना foreach से लागू की आपूर्ति कर सकते, List<T> के लेखकों प्रदर्शन के एक मामूली व्यापार बंद का सामना करना पड़ा बनाम अर्थशास्त्र। उस समय, क्योंकि सी # ने चर-प्रकार के अनुमान का समर्थन नहीं किया था, List<T>.GetEnumerator से लौटाए गए मान का उपयोग करने वाले किसी भी कोड को IEnumerator<T> या List<T>.Enumerator प्रकार का एक चर घोषित करना होगा। पूर्व प्रकार का उपयोग करने वाला कोड व्यवहार करेगा जैसा कि List<T>.Enumerator एक संदर्भ प्रकार था, और बाद वाले का उपयोग करने वाला प्रोग्रामर यह महसूस करने के लिए माना जा सकता था कि यह एक संरचना प्रकार था। जब सी # जोड़ा प्रकार अनुमान, हालांकि, धारणा पकड़ने के लिए बंद कर दिया। उस प्रकार के अस्तित्व के बारे में जानने वाले प्रोग्रामर के बिना कोड List<T>.Enumerator का उपयोग करके कोड आसानी से समाप्त हो सकता है।

यदि सी # कभी भी स्ट्रक्चर-विधि विशेषता को परिभाषित करने के लिए उपयोग किया गया था जिसका उपयोग उन तरीकों को टैग करने के लिए किया जा सकता था जिन्हें केवल पढ़ने के लिए संरचनाओं पर अनावश्यक नहीं किया जाना चाहिए, और यदि List<T>.Enumerator इसका उपयोग किया गया है, तो आपके जैसे कोड ठीक से उपज सकते हैं MoveNext पर कॉल पर संकलन-समय त्रुटि, जो कि फर्जी व्यवहार प्रदान करती है। हालांकि, मुझे ऐसी विशेषता जोड़ने की कोई विशेष योजना नहीं है।

संबंधित मुद्दे