मैं पैरेंट स्कोप में वैरिएबल के समान चाइल्ड वेरिएबल की घोषणा क्यों कर सकता हूं?


23

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

var x = 1;
Action<int> myAction = (x) => { Console.WriteLine(x); };

जब मैंने दोहराव देखा, तो मुझे यह देखकर आश्चर्य हुआ कि कोड संकलित किया गया और पूरी तरह से भाग गया, जो व्यवहार नहीं है जो मैं C # में गुंजाइश के बारे में जो जानता हूं उसके आधार पर उम्मीद करूंगा। कुछ त्वरित Googling ने SO प्रश्नों को बदल दिया, जो शिकायत करते हैं कि समान कोड एक त्रुटि उत्पन्न करता है , जैसे कि लैम्ब्डा स्कोप क्लैरिफिकेशन । (मैंने उस सैंपल कोड को अपने आईडीई में पेस्ट किया, यह देखने के लिए कि क्या यह चलेगा, बस यह सुनिश्चित करने के लिए; यह पूरी तरह से चलता है।) इसके अलावा, जब मैं विज़ुअल स्टूडियो में नाम बदलकर डायल करता हूं, तो पहला xनाम संघर्ष के रूप में उजागर होता है।

यह कोड क्यों काम करता है? मैं विजुअल स्टूडियो 2019 के साथ C # 8 का उपयोग कर रहा हूं।


1
लैम्ब्डा को संकलक द्वारा उत्पन्न एक वर्ग पर एक विधि में ले जाया जाता है, और इस प्रकार xउस पद्धति का पूरा पैरामीटर कार्यक्षेत्र से बाहर चला जाता है। उदाहरण के लिए शार्पलैब देखें ।
लास वी। कार्लसन

6
यहां यह ध्यान देने योग्य है कि यह C # 7.3 को लक्षित करते समय संकलित नहीं होगा, इसलिए यह C # 8 के लिए अनन्य प्रतीत होता है।
जोनाथन चेस

लिंक किए गए प्रश्न में कोड भी शार्पलैब में ठीक संकलित करता है । यह हालिया बदलाव हो सकता है।
लास वी। कार्लसन

जवाबों:


26

यह कोड क्यों काम करता है? मैं विजुअल स्टूडियो 2019 के साथ C # 8 का उपयोग कर रहा हूं।

आपने अपने प्रश्न का उत्तर दिया है! ऐसा इसलिए है क्योंकि आप C # 8 का उपयोग कर रहे हैं।

7 के माध्यम से C # 1 से नियम था: एक साधारण नाम का उपयोग एक ही स्थानीय दायरे में दो अलग-अलग चीजों का मतलब करने के लिए नहीं किया जा सकता है। (वास्तविक नियम इससे थोड़ा अधिक जटिल था लेकिन यह वर्णन करना कि कैसे थकाऊ है, विवरण के लिए सी # विनिर्देश देखें।)

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

class C 
{
  int x;
  void M()
  {
    x = 123;
    if (whatever)
    {
      int x = 356;
      ...

और अब हमारे पास एक ऐसी स्थिति है जहां शरीर के अंदर M, xदोनों का मतलब है this.xऔर स्थानीय x

हालांकि इस इरादे से, इस नियम के साथ कई समस्याएं थीं:

  • यह कल्पना करने के लिए लागू नहीं किया गया था। ऐसी परिस्थितियाँ थीं जहाँ एक सरल नाम का उपयोग किया जा सकता था, जैसे कि, एक प्रकार और एक संपत्ति दोनों, लेकिन इन्हें हमेशा त्रुटियों के रूप में चिह्नित नहीं किया गया था क्योंकि त्रुटि का पता लगाने में तर्क त्रुटिपूर्ण था। (निचे देखो)
  • त्रुटि संदेश भ्रामक रूप से लिखे गए थे, और असंगत रूप से रिपोर्ट किए गए थे। इस स्थिति के लिए कई अलग-अलग त्रुटि संदेश थे। उन्होंने असंगत रूप से अपराधी की पहचान की; अर्थात् , कभी-कभी आंतरिक उपयोग को बाहर कहा जाता था, कभी-कभी बाहरी , और कभी-कभी यह केवल भ्रमित था।

मैंने रोजलिन को इस तरह छांटने के लिए फिर से लिखने का प्रयास किया; मैंने कुछ नए त्रुटि संदेश जोड़े, और पुराने को लगातार त्रुटि के बारे में बताया। हालाँकि, यह प्रयास बहुत कम था, बहुत देर से।

C # टीम ने C # 8 के लिए फैसला किया कि पूरे नियम से अधिक भ्रम पैदा हो रहा था, क्योंकि यह रोक रहा था, और नियम भाषा से सेवानिवृत्त हो गया था। (रिटायरमेंट होने पर यह निर्धारित करने के लिए धन्यवाद जॉनथॉन चेस।)

यदि आप इस समस्या के इतिहास को जानने के इच्छुक हैं और मैंने इसे ठीक करने का प्रयास किया है, तो मेरे द्वारा लिखे गए इन लेखों को देखें:

https://ericlippert.com/2009/11/02/simple-names-are-not-so-simple/

https://ericlippert.com/2009/11/05/simple-names-are-not-so-simple-part-two/

https://ericlippert.com/2014/09/25/confusing-errors-for-a-confusing-feature-part-one/

https://ericlippert.com/2014/09/29/confusing-errors-for-a-confusing-feature-part-two/

https://ericlippert.com/2014/10/03/confusing-errors-for-a-confusing-feature-part-three/

भाग तीन के अंत में मैंने नोट किया कि इस फ़ीचर और "कलर कलर" फ़ीचर के बीच एक इंटरैक्शन भी था - वह यह है कि फ़ीचर:

class C
{
  Color Color { get; set; }
  void M()
  {
    Color = Color.Red;
  }
}

यहाँ हमने सरल नाम Colorका प्रयोग किया है this.Colorऔर दोनों प्रकार का उल्लेख करने के लिए Color; विनिर्देश के एक सख्त पढ़ने के अनुसार यह एक त्रुटि होनी चाहिए, लेकिन इस मामले में कल्पना गलत थी और इरादा इसे अनुमति देने के लिए था, क्योंकि यह कोड असंदिग्ध है और डेवलपर को इसे बदलने के लिए यह घबराहट होगी।

मैंने उस लेख को इन दोनों नियमों के बीच की सभी अजीबोगरीब मुलाकातों का वर्णन करते हुए कभी नहीं लिखा, और अब ऐसा करना थोड़ा व्यर्थ होगा!


प्रश्न में कोड C # 6, 7, 7.1, 7.2, और 7.3 के लिए संकलित करने में विफल रहता है, जिससे "CS0136: 'x' नामक स्थानीय या पैरामीटर को इस दायरे में घोषित नहीं किया जा सकता क्योंकि वह नाम ..."। ऐसा लगता है कि यह नियम अभी भी C # 8 तक लागू है
जोनाथन चेस

@JonathonChase: धन्यवाद!
एरिक लिपर्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.