अद्यतन
ठीक है, मूल रूप से मैं ने कहा, "संकलक एक foreach
पाश करने के लिए डाले कहते हैं।" यह सख्ती से सटीक नहीं है: यह हमेशा कास्ट नहीं करेगा। वास्तव में क्या हो रहा है यहाँ है।
सभी की
सबसे पहले, आप इस foreach
पाश है जब:
int x;
[object] e;
try
{
e = collection.GetEnumerator();
while (e.MoveNext())
{
x = [cast if possible]e.Current;
}
}
finally
{
[dispose of e if necessary]
}
:
foreach (int x in collection)
{
}
... यहाँ क्या संकलक बनाता है की बुनियादी रूपरेखा (में छद्म सी #) है क्या? मैं आपको सुन रहा हूँ। आप [object]
से क्या मतलब है? "
यहाँ मैं क्या मतलब है। foreach
पाश वास्तव में आवश्यकता है कोई इंटरफ़ेस है, जो यह वास्तव में एक छोटा सा जादुई है का मतलब है। यह केवल आवश्यकता है कि वस्तु के प्रकार के प्रगणित किया जा रहा एक को उजागर करता है GetEnumerator
विधि, जो बदले में कुछ प्रकार है कि एक MoveNext
और एक Current
संपत्ति प्रदान करता है का एक उदाहरण प्रदान करनी चाहिए।
तो मैं [object]
लिखा था क्योंकि e
के प्रकार के जरूरी IEnumerator<int>
के एक कार्यान्वयन, या यहाँ तक +०१२३८६५५९७७ होने की जरूरत नहीं है- जिसका अर्थ यह भी है कि इसे IDisposable
(इसलिए [dispose if necessary]
भाग) को लागू करना आवश्यक नहीं है।
इस प्रश्न का उत्तर देने के उद्देश्य से हम जिस कोड की परवाह करते हैं उसका वह हिस्सा वह हिस्सा है जहां मैंने [cast if possible]
लिखा था। जाहिर है, क्योंकि कंपाइलर को वास्तविक IEnumerator<T>
या IEnumerator
कार्यान्वयन की आवश्यकता नहीं है, e.Current
का प्रकार T
, object
या बीच में कुछ भी नहीं माना जा सकता है।इसके बजाए, संकलक संकलन समय पर GetEnumerator
द्वारा लौटाए गए प्रकार के आधार पर e.Current
का प्रकार निर्धारित करता है। फिर निम्न होता है:
- हैं प्रकार स्थानीय चर (उपरोक्त उदाहरण में
x
) के प्रकार, एक सीधे काम किया जाता है।
- हैं प्रकार परिवर्तनीय स्थानीय चर के प्रकार (जिसके द्वारा मेरा मतलब है, एक कानूनी डाली
x
के प्रकार के e.Current
के प्रकार से मौजूद है) करने के लिए, एक डाली डाला जाता है।
- अन्यथा, कंपाइलर एक त्रुटि उठाएगा।
तो एक List<int?>
से अधिक की गणना की स्थिति में, हम चरण 2 पर हो और संकलक देखता है कि List<int?>.Enumerator
प्रकार के Current
संपत्ति प्रकार int?
, जो स्पष्ट रूप से int
लिए डाली जा सकती है, की है।
तो लाइन इस के बराबर करने के लिए संकलित किया जा सकता:
x = (int)e.Current;
अब, क्या करता है Nullable<int>
के लिए की तरह explicit
ऑपरेटर देखो?
परावर्तक के अनुसार:
public static explicit operator T(T? value)
{
return value.Value;
}
तो the behavior described by Kent, है जहाँ तक मैं बता सकता हूँ, बस एक संकलक अनुकूलन: (int)e.Current
स्पष्ट डाली inlined है।
आपके प्रश्न के सामान्य उत्तर के रूप में, मैं अपने दावे से चिपक जाता हूं कि कंपाइलर आवेषण foreach
लूप में आवश्यक है जहां आवश्यक हो।
मूल उत्तर
संकलक स्वचालित रूप से सम्मिलित करता डाले जहां सरल कारण के लिए एक foreach
पाश में की जरूरत है कि जेनरिक से पहले वहाँ था कोई IEnumerable<T>
इंटरफेस, केवल IEnumerable
*। IEnumerable
इंटरफ़ेस IEnumerator
का खुलासा करता है, जो बदले में Current
प्रकार object
की संपत्ति प्रदान करता है।
तब तक जब तक कि संकलक ने आपके लिए कास्ट नहीं किया, पुराने समय में, foreach
का उपयोग करने का एकमात्र तरीका object
के स्थानीय चर के साथ किया गया था, जो स्पष्ट रूप से चूसा होता।
* और वास्तव में, foreach
doesn't require any interface at all - केवल GetEnumerator
विधि और एक MoveNext
और एक Current
साथ एक साथ लिखें।
त्रुटि मुझे सामान्य लगती है। आप int से परिवर्तित कर सकते हैं? int करने के लिए, लेकिन आप एक int से बूल परिवर्तित नहीं कर सकते हैं। –
@ एड्रियन मुझे नहीं लगता कि यह स्पष्टीकरण सही है। अगर मैं बूल के बजाय स्ट्रिंग था तो क्या होगा। Int को स्ट्रिंग में परिवर्तित किया जा सकता है लेकिन कंपाइलर विरोध प्रदर्शन करेगा। – nan
Int को स्ट्रिंग में परिवर्तित नहीं किया जा सकता है। कोई अंतर्निहित या स्पष्ट रूपांतरण परिभाषित नहीं किया गया है। यदि आप ToString() विधि का जिक्र कर रहे हैं तो यह एक अलग बात है। –