दरअसल, यह प्रदर्शन कारणों से है। बीसीएल टीम ने लॉट पर इस बिंदु पर शोध के पहले निर्णय लेने से पहले कि आप सही तरीके से एक संदिग्ध और खतरनाक अभ्यास के रूप में कॉल करने का निर्णय लेते हैं: एक परिवर्तनीय मूल्य प्रकार का उपयोग किया।
आप पूछते हैं कि यह मुक्केबाजी का कारण क्यों नहीं है। ऐसा इसलिए है क्योंकि सी # कंपाइलर फोरैच लूप में आईन्यूमेरेबल या आईन्यूमेरेटर को बॉक्स स्टफ पर कोड जेनरेट नहीं करता है अगर यह इससे बच सकता है!
जब हम
foreach(X x in c)
देख पहली बात हम करते हैं, तो ग एक विधि GetEnumerator कहा जाता है देखने के लिए जाँच है। यदि ऐसा होता है, तो हम यह देखने के लिए जांचते हैं कि जिस प्रकार से यह लौटाता है, उसमें मूवनेक्स्ट और प्रॉपर्टी चालू है। यदि ऐसा होता है, तो फ़ोरैच लूप पूरी तरह से उन विधियों और गुणों के लिए सीधे कॉल का उपयोग करके उत्पन्न होता है। केवल अगर "पैटर्न" का मिलान नहीं किया जा सकता है तो क्या हम इंटरफेस की तलाश में वापस आते हैं।
इसमें दो वांछनीय प्रभाव हैं।
सबसे पहले, अगर संग्रह, स्याही का संग्रह कहता है, लेकिन जेनेरिक प्रकारों का आविष्कार करने से पहले लिखा गया था, तो यह मुक्केबाजी के मुक्केबाजी दंड को ऑब्जेक्ट करने के लिए वर्तमान के मूल्य को नहीं लेता है और फिर इसे int में अनबॉक्स कर रहा है। यदि वर्तमान एक ऐसी संपत्ति है जो एक int लौटाती है, तो हम इसका इस्तेमाल करते हैं।
दूसरा, यदि गणनाकर्ता एक मान प्रकार है तो यह एननेमेरेटर के लिए गणनाकर्ता को बॉक्स नहीं करता है।
जैसा कि मैंने कहा, बीसीएल टीम इस पर अनुसंधान के एक बहुत कुछ किया और पाया कि समय के विशाल बहुमत, आवंटन और प्रगणक deallocating के दंड इतना बड़ा है कि यह यह एक मान प्रकार बनाने लायक था , भले ही ऐसा करने से कुछ पागल कीड़े हो सकती हैं।
उदाहरण के लिए, इस पर विचार करें:
struct MyHandle : IDisposable { ... }
...
using (MyHandle h = whatever)
{
h = somethingElse;
}
आप काफी ठीक ही विफल ज उत्परिवर्तित करने का प्रयास उम्मीद होती है, और वास्तव में यह होता है। कंपाइलर का पता लगाता है कि आप किसी ऐसे लंबित निपटारे के मूल्य को बदलने की कोशिश कर रहे हैं, जिसमें ऐसा लंबित निपटान है, और ऐसा करने से ऑब्जेक्ट का निपटारा करने की आवश्यकता हो सकती है जिसे वास्तव में निपटान नहीं किया जा सकता है।
अब मान लीजिए कि आप था:
struct MyHandle : IDisposable { ... }
...
using (MyHandle h = whatever)
{
h.Mutate();
}
यहाँ क्या होता है? आप उचित रूप से उम्मीद कर सकते हैं कि संकलक ऐसा करेगा यदि एच एक पाठक क्षेत्र था: make a copy, and mutate the copy यह सुनिश्चित करने के लिए कि विधि उस मूल्य में सामान को फेंक न दे जिस पर निपटान की आवश्यकता है। यह है चाहे
using (Enumerator enumtor = whatever)
{
...
enumtor.MoveNext();
...
}
हमें उम्मीद है कि एक का उपयोग कर ब्लॉक अंदर एक MoveNext कर अगले एक करने के लिए प्रगणक पर आ जाएगा:
हालांकि, इस बारे में हमारे अंतर्ज्ञान के साथ संघर्ष क्या यहाँ होने के लिए चाहिए एक संरचना या एक रेफ प्रकार।
दुर्भाग्यवश, सी # कंपाइलर में आज एक बग है। यदि आप इस स्थिति में हैं तो हम चुनते हैं कि कौन सी रणनीति असंगत रूप से पालन करें। व्यवहार आज:
यदि मान टाइप चर जा रहा है एक विधि के माध्यम से उत्परिवर्तित एक सामान्य स्थानीय तो यह सामान्य रूप से उत्परिवर्तित
है, लेकिन अगर यह एक फहराया स्थानीय है (यह एक closed- है, क्योंकि एक अज्ञात फ़ंक्शन या इटेटरेटर ब्लॉक में परिवर्तनीय) तो स्थानीय वास्तव में केवल पढ़ने के लिए फ़ील्ड के रूप में उत्पन्न होता है, और गियर जो सुनिश्चित करता है कि एक प्रतिलिपि पर उत्परिवर्तन होता है।
दुर्भाग्यवश इस मामले पर spec थोड़ा मार्गदर्शन प्रदान करता है। स्पष्ट रूप से कुछ तोड़ दिया गया है क्योंकि हम इसे असंगत रूप से कर रहे हैं, लेकिन सही क्या करना है बिल्कुल स्पष्ट नहीं है। इस पर दौड़ते हुए दूसरों के लिए
संबंधित पृष्ठों: http://stackoverflow.com/questions/384511/enumerator-implementation-use-struct-or-class http://www.eggheadcafe.com/software/ एस्पनेट/31702392/सी-कंपाइलर-चुनौती - s.aspx –