2010-09-09 21 views
19
static void Main(string[] args) 
    { 
     List<int> listArray = new List<int>(); 
     listArray.Add(100); 
     foreach (int item in listArray) 
      Console.WriteLine(item); 
    } 

क) foreach बयान listArray's IEnumerable<int>.GetEnumerator() कार्यान्वयन की आवश्यकता होने पर, यह इसके listArray.GetEnumerator() या IEnumerable<int>.GetEnumerator() या IEnumerable.GetEnumerator() के माध्यम से फोन करता है?foreach कॉल GetEnumerator() कैसे कॉल करता है? IENumerable संदर्भ के माध्यम से या ... के माध्यम से?

ख) इसी प्रकार, जब foreach संदर्भ listArray's IEnumerable<int>.GetEnumerator() द्वारा दिया वस्तु, यह इस वस्तु IEnumerator या IEnumerator<int> संदर्भ प्रकार के माध्यम से संदर्भ करता है?

धन्यवाद

संपादित करें:

मेरे सवालों का इस पाठ बोली जाएगा में से कुछ:

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

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

ओ तो GetEnumerator विधि की वापसी प्रकार ई एक वर्ग नहीं है, struct या इंटरफ़ेस प्रकार, एक त्रुटि उत्पादित है और आगे नहीं चरणों लिया है।

ओ सदस्य लुकअप पहचानकर्ता वर्तमान के साथ ई पर किया गया है और प्रकार तर्क हैं। यदि सदस्य लुकअप कोई मिलान नहीं करता है, तो परिणाम त्रुटि है, या नतीजा है जो सार्वजनिक उदाहरण संपत्ति को छोड़कर पढ़ने की अनुमति देता है, एक त्रुटि उत्पन्न होती है और कोई और कदम नहीं उठाया जाता है।

o सदस्य लुकअप पहचानकर्ता MoveNext और कोई प्रकार तर्कों के साथ ई पर किया जाता है। यदि सदस्य लुकअप कोई मिलान नहीं करता है, तो परिणाम त्रुटि है, या परिणाम किसी विधि समूह को छोड़कर कुछ भी है, एक त्रुटि उत्पादित है और कोई और कदम नहीं लिया गया है।

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

ओ संग्रह प्रकार, एक्स है प्रगणक प्रकार ई है, और तत्व प्रकार वर्तमान संपत्ति का प्रकार है।

  • अन्यथा, एक गणनीय इंटरफेस के लिए जाँच: ओ यदि वहाँ वास्तव में एक प्रकार टी इस तरह के एक अंतर्निहित इंटरफ़ेस System.Collections.Generic.IEnumerable को एक्स से रूपांतरण होता है, तो संग्रह प्रकार इस इंटरफेस है, प्रगणक प्रकार इंटरफ़ेस System.Collections.Generic.IEnumerator, है और तत्व प्रकार,

  • अन्यथा टी

    है अगर एक से अधिक इस प्रकार टी है, तो त्रुटि उत्पन्न होती है और कोई और कदम नहीं उठाए जाते हैं।

  • अन्यथा, अगर वहाँ System.Collections.IEnumerable इंटरफ़ेस के लिए एक्स से एक अंतर्निहित रूपांतरण है, तो संग्रह प्रकार इस इंटरफेस, प्रगणक प्रकार System.Collections.IEnumerator है इंटरफ़ेस , और है तत्व प्रकार वस्तु है।

  • अन्यथा, एक त्रुटि उत्पन्न होती है और कोई और कदम नहीं लिया जाता है।

1) एरिक Lippert से

उद्धरण:

विकल्प (1) सही है। ध्यान दें कि यह का अर्थ है कि वापस आने वाला गणक एक अनबॉक्स किए गए परिवर्तनीय संरचना है।

तथ्य यह एक परिवर्तनशील struct बहुत ही वास्तविक असर पड़ता है अगर आप कुछ चारों ओर struct गुजर जैसे कि यह एक संदर्भ प्रकार थे जैसे मूर्ख करना है कि; इसे मान द्वारा प्रतिलिपि बनाई जाएगी, संदर्भ के अनुसार नहीं।

http://en.csharp-online.net/ECMA-334:_15.8.4_The_foreach_statement से:

foreach (एक्स में वी वी) एम्बेडेड बयान

तो करने के लिए विस्तारित किया गया है:

{ 
    E e = ((C)(x)).GetEnumerator(); 
    try { 
     V v; 
     while (e.MoveNext()) { 
     v = (V)(T)e.Current; 
     embedded-statement 
     } 
    } 
    finally { 
     … // Dispose e 
    } 
} 

चर ई करने के लिए या दिखाई नहीं देता है अभिव्यक्ति एक्स या एम्बेडेड कथन या किसी अन्य स्रोत के लिए सुलभकार्यक्रम के 0 कोड।

listArray के मामले में, लौट आए प्रगणक में सहेजा जाता है (यानी अपने मूल्य सहेजा जाता है) अलग-अलग e (इस प्रकार चर e एक परिवर्तनशील struct है) .लेकिन ऊपर अंश के अनुसार, e मेरे स्रोत के लिए नहीं पहुंच नहीं है कोड, तो मैं इस संरचना को चारों ओर कैसे पारित कर पाऊंगा (जब तक कि मैं कोड लिखता हूं जो मैन्युअल रूप से foreach कथन स्वचालित रूप से करता है)?

2)

सदस्य देखने पहचानकर्ता वर्तमान और कोई प्रकार तर्क के साथ ई पर किया जाता है। यदि सदस्य लुकअप कोई मिलान नहीं करता है, तो परिणाम एक त्रुटि है, या नतीजा कुछ भी है जो सार्वजनिक आवृत्ति संपत्ति को छोड़कर पढ़ने की अनुमति देता है, एक त्रुटि उत्पन्न होती है और आगे के कदम नहीं उठाए जाते हैं।

ऐसा लगता है कि अगर हम कक्षा में GetEnumerator लागू (X) ही है, तो Current भी वर्ग (E) में, लागू किया जाना चाहिए ही (इस प्रकार E स्पष्ट Current लागू नहीं होना चाहिए) के बाद से संकलक नहीं होगा उन मामलों में IEnumerator<T>/IEnumerator इंटरफ़ेस की जांच करने के लिए परेशान करें जहां सदस्य लुकअप (E पर पहचानकर्ता Current के साथ) कोई मिलान नहीं करता है?

3)

यदि वहाँ वास्तव में एक प्रकार टी इस तरह के इंटरफ़ेस System.Collections.Generic.IEnumerable को एक्स से एक अंतर्निहित रूपांतरण होता है, तो संग्रह प्रकार इस इंटरफेस, है प्रगणक प्रकार इंटरफ़ेस System.Collections.Generic.IEnumerator है, और तत्व प्रकार टी

ऊपर के अनुसार,है अगर foreachIEnumerable<T> इंटरफेस के लिए जाँच करने के लिए है, तोCurrent के IEnumerator<T> संस्करण का उपयोग करेगा? इस प्रकार, यदि E स्पष्ट Current की IEnumerator<T> संस्करण को भी लागू और अगर यह भी वर्ग अपने आप में Current का एक और संस्करण को भी लागू foreach हमेशा Current की IEnumerable<T> संस्करण फोन करेगा?

4)

GetEnumerator विधि इनमें से किसी एक लौटने के रूप में दर्ज है:

http://msdn.microsoft.com/en-us/library/x854yt9s.aspx

क्या आप बहुवचन में के रूप में इन की एक (मतलब है)? आपके द्वारा प्रदान किया गया लिंक कहता है GetEnumerator (जैसा कि List<T> द्वारा कार्यान्वित किया गया है) केवल struct प्रकार देता है।

5)

जी। संग्रह प्रकार एक्स है, प्रगणक प्रकार ई है, और तत्व प्रकार वर्तमान संपत्ति

शायद एक बेकार सवाल के प्रकार है - ऊपर के अनुसार, foreach जाँच नहीं करता तत्वों कुछ उपयोगकर्ता- किस प्रकार परिभाषित संग्रह वास्तव में स्टोर करता है, लेकिन इसके बजाय मानता है कि तत्वों का प्रकार Current संपत्ति द्वारा लौटाए गए प्रकार के समान है?

+0

क्या आपने स्वयं को खोजने के लिए एक सरल परीक्षा लिखने पर विचार किया है? यह एक वर्ग लिखने के लिए बहुत छोटा होगा जो 'IEnumerable.GetEnumerator()' और GetEnumerator() लागू करता है और अलग-अलग समकक्षों को वापस भेजता है। – Aren

+0

मैंने आपके अतिरिक्त प्रश्नों को हल करने के लिए अपना उत्तर अपडेट कर दिया है। –

उत्तर

15

(क) foreach बयान listArray के IEnumerable.GetEnumerator() कार्यान्वयन की आवश्यकता होने पर, यह इसके माध्यम से (1) listArray.GetEnumerator() या (2) IEnumerable.GetEnumerator() या (3) IEnumerable.GetEnumerator फोन करता है() ?

विकल्प (1) सही है। ध्यान दें कि इसका मतलब है कि वापस आने वाला गणक एक अनबॉक्स किए गए परिवर्तनीय संरचना है। GetEnumerator विधि इनमें से किसी एक लौटने के रूप में दर्ज है:

http://msdn.microsoft.com/en-us/library/x854yt9s.aspx

तथ्य यह है कि यह एक अस्थायी struct बहुत ही वास्तविक प्रभाव है अगर आप कुछ struct के आसपास गुजर जैसे कि यह एक संदर्भ प्रकार थे जैसे मूर्ख करना है; यह मूल्य द्वारा प्रतिलिपि बनाई जाएगी, संदर्भ के अनुसार नहीं।

(1) लेकिन इसके बाद के संस्करण अंश के अनुसार, ई, तो कैसे मैं इस पारित करने में सक्षम हो जाएगा चारों ओर struct (स्वचालित रूप से जब तक मुझे लगता है कि मैन्युअल रूप से करता है कोड लिखने क्या foreach बयान करता है) मेरे स्रोत कोड के लिए नहीं पहुंच नहीं है ?

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

(2) ऐसा लगता है कि अगर हम दसवीं कक्षा में ही GetEnumerator लागू है, तो वर्तमान भी वर्ग ई अपने आप में लागू किया जाना चाहिए के बाद से संकलक मामलों में जहां में स्पष्ट इंटरफेस सदस्यों के लिए जाँच करने के लिए परेशान नहीं करेगा सदस्य लुकअप एक मैच का उत्पादन नहीं करता है?

सही।

(3) यदि foreach IEnumerable<T> इंटरफेस के लिए जाँच करने के लिए है, तो foreach हमेशा वर्तमान के IEnumerator<T> संस्करण का उपयोग करेंगे? इस प्रकार, यदि ई वर्तमान में IEnumerator<T> संस्करण का स्पष्ट रूप से लागू करता है और यदि यह कक्षा में वर्तमान के किसी अन्य संस्करण को भी लागू करता है, तो foreach हमेशा वर्तमान के IEnumerable<T> संस्करण को कॉल करेगा?

सही। यदि आप उस बिंदु पर पहुंच जाते हैं जहां हम इंटरफ़ेस को देख रहे हैं तो हम इंटरफ़ेस का उपयोग करने जा रहे हैं।

(4) क्या आप

मैं मतलब है कि यह struct का एक उदाहरण वापस आ जाएगी "इनमें से एक" मतलब है।

(5) उपर्युक्त के अनुसार, foreach यह जांच नहीं करता कि कुछ उपयोगकर्ता परिभाषित संग्रह वास्तव में किस प्रकार के तत्वों को संग्रहीत करता है, लेकिन इसके बजाय यह मानता है कि तत्वों का प्रकार वर्तमान संपत्ति द्वारा लौटाए गए प्रकार के समान है?

सही। यह जांचता है कि कास्ट सफल होता है। उदाहरण के लिए, अगर आप कहते हैं कि

foreach(int x in myObjects) 

जहां myObjects आप एक प्रगणक जिसका वर्तमान प्रकार वस्तु का है, तो पाश मानता है कि प्रत्येक वस्तु सफलतापूर्वक int करने के लिए डाली जा सकती है, देता है, और है कि अगर गलत है कार्यावधि में एक अपवाद फेंकता । लेकिन अगर आप इसी तरह से कहते हैं:

foreach(string x in myInts) 

तो संकलक नोट करेंगे कि अगर वर्तमान किसी पूर्णांक रिटर्न तो संग्रह कभी नहीं एक स्ट्रिंग है, और कार्यक्रम संकलित करने के लिए असफल हो जायेगी।

(ख) इसी प्रकार, जब foreach संदर्भ listArray के IEnumerable.GetEnumerator() द्वारा दिया वस्तु, यह IEnumerator या IEnumerator संदर्भ प्रकार के माध्यम से इस वस्तु को संदर्भित करता है?

सवाल प्रश्न (2) के पहले प्रश्न के उत्तर पर भविष्यवाणी की गई है।चूंकि प्रश्न झूठ पर भविष्यवाणी की गई है, इसलिए इसे समझदारी से उत्तर नहीं दिया जा सकता है।

+0

क्या आप मेरी संपादित पोस्ट देख सकते हैं? – user437291

+0

आपकी मदद के लिए सभी को धन्यवाद – user437291

13

भाषा विनिर्देश, धारा 8.8.4 में foreach का व्यवहार वर्तनी है। संक्षेप

foreach में (अभिव्यक्ति में टी टी)

  • तो अभिव्यक्ति एक सरणी है *, IEnumerable इंटरफ़ेस का उपयोग (* नीचे देखें एरिक Lippert की टिप्पणी।)
  • वरना अगर अभिव्यक्ति है GetEnumerator विधि,
  • अन्य अभिव्यक्तिIEnumerable<T> में कनवर्ट करने योग्य है, उस इंटरफ़ेस और IEnumerator<T> (और संबंधित विधियों) का उपयोग करें
  • वरना अगर अभिव्यक्तिIEnumerable के लिए परिवर्तनीय है, कि इंटरफेस और IEnumerator (और संबद्ध तरीकों)

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

+10

ध्यान दें कि पहला बुलेट बिंदु संभावित रूप से भ्रामक है। सी # कंपाइलर द्वारा उत्पन्न कोड * वास्तव में * आईई इंटरफ़ेस का उपयोग नहीं करता है जब फ़ोरैच के साथ सरणी (या स्ट्रिंग!) का गणना करता है। इसके बजाय, यह वही उत्पन्न करता है "के लिए (int i = 0; i * के रूप में मानता है * लेकिन वास्तव में * कोड * उस तरह से उत्पन्न नहीं करता है। –

+1

@Eric, यह दिलचस्प है! –

6

सी # 3.0 भाषा कल्पना (धारा 8.8.4।) से:

एक foreach बयान के संकलन समय प्रसंस्करण पहली अभिव्यक्ति का संग्रह प्रकार, प्रगणक प्रकार और तत्व प्रकार निर्धारित करता है। इस संकल्प के रूप में निम्नानुसार आगे बढ़ता है:

  1. तो अभिव्यक्ति के प्रकार के एक्स एक सरणी टाइप है तो System.Collections.IEnumerable इंटरफ़ेस के लिए एक्स से एक अंतर्निहित संदर्भ रूपांतरण (के बाद से System.Array इस इंटरफेस को लागू करता है) है। संग्रह प्रकार सिस्टम है। चयन। INumerable इंटरफ़ेस, गणनाकर्ता प्रकार सिस्टम है। चयन। IEnumerator इंटरफ़ेस और तत्व प्रकार सरणी प्रकार एक्स का तत्व प्रकार है।
  2. अन्यथा, निर्धारित प्रकार एक्स एक उपयुक्त GetEnumerator विधि है या नहीं:

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

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

    सी। यदि GetEnumerator विधि का रिटर्न टाइप ई क्लास, स्ट्रक्चर या इंटरफ़ेस प्रकार नहीं है, तो एक त्रुटि उत्पन्न होती है और कोई और कदम नहीं उठाया जाता है।

    डी। सदस्य लुकअप पहचानकर्ता वर्तमान और कोई प्रकार के तर्क के साथ ई पर किया जाता है। यदि सदस्य लुकअप कोई मिलान नहीं करता है, तो परिणाम एक त्रुटि है, या परिणाम सार्वजनिक उदाहरण संपत्ति को छोड़कर कुछ भी है जो पढ़ने की अनुमति देता है, एक त्रुटि उत्पन्न होती है और कोई और कदम नहीं उठाया जाता है।

    ई। सदस्य लुकअप पहचानकर्ता MoveNext और कोई प्रकार तर्क के साथ ई पर किया जाता है। यदि सदस्य लुकअप कोई मिलान नहीं करता है, तो परिणाम एक त्रुटि है, या परिणाम एक विधि समूह को छोड़कर कुछ भी है, एक त्रुटि उत्पन्न होती है और कोई और कदम नहीं उठाया जाता है।

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

    जी। संग्रह प्रकार एक्स है, एन्यूमेरेटर प्रकार ई है, और तत्व प्रकार वर्तमान संपत्ति का प्रकार है।

सारांश में, संकलक में कार्य करता है के रूप में यदि foreach निम्नलिखित कोड थे, बहुरूपी कॉल करने और (यदि हो तो) परिभाषित गणनीय इंटरफ़ेस परिभाषा को देखकर उचित प्रकार और विधियों का निर्धारण करने के:

var iterator = listArray.GetEnumerator(); 
while(iterator.MoveNext()) 
{ 
    var item = iterator.Current; 
    Console.WriteLine(item); 
} 
+3

बेशक अंक गणना करने के लिए कोड। साथ ही, ध्यान दें कि यदि संग्रह एक सरणी या स्ट्रिंग है तो यह उत्पन्न कोड नहीं है। –

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