C # में const पैरामीटर की अनुमति क्यों नहीं है?


102

यह विशेष रूप से C ++ डेवलपर्स के लिए अजीब लगता है। C ++ में हम एक पैरामीटर को चिह्नित करते constथे ताकि यह सुनिश्चित किया जा सके कि इसकी स्थिति को विधि में नहीं बदला जाएगा। अन्य सी ++ विशिष्ट कारण भी हैं, जैसे const refकि रिफ द्वारा पास करने के लिए पास होना और यह सुनिश्चित करना कि राज्य नहीं बदला जाएगा। लेकिन हम C # में विधि पैरामीटर const के रूप में चिह्नित क्यों नहीं कर सकते हैं?

मैं निम्नलिखित की तरह अपनी पद्धति की घोषणा क्यों नहीं कर सकता?

    ....
    static void TestMethod1(const MyClass val)
    {}
    ....
    static void TestMethod2(const int val)
    {}
    ....

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

3
इस सवाल पर एक बड़ी चर्चा: "c # में
कॉन्स्टेंस

मूल्य प्रकार के लिए [बाहर / रेफरी] है, लेकिन संदर्भ प्रकार नहीं हैं। यह एक दिलचस्प सवाल है।
केनी

4
यह प्रश्न C # और भाषा-अज्ञेय टैग दोनों कैसे हो सकता है?
CJ7

1
बिना साइड इफेक्ट के अपरिवर्तनीय डेटा और फ़ंक्शंस आसान हैं। आप F # fsharpforfunandprofit.com/posts/is-your-language-unreasonable
कर्नल पैनिक

जवाबों:


59

अन्य अच्छे उत्तरों के अलावा, मैं अभी तक एक और कारण जोड़ूंगा कि C # में C- स्टाइल की कमी नहीं डाली जाए। तुमने कहा था:

हम पैरामीटर को कब्ज के रूप में चिह्नित करते हैं ताकि यह सुनिश्चित हो सके कि इसकी स्थिति को विधि में नहीं बदला जाएगा।

अगर वास्तव में कास्ट ने ऐसा किया, तो यह बहुत अच्छा होगा। कास्ट ऐसा नहीं करता है। कास्ट एक झूठ है!

कॉन्स्ट कोई गारंटी नहीं देता है कि मैं वास्तव में उपयोग कर सकता हूं। मान लीजिए आपके पास एक तरीका है जो एक कास्ट चीज़ लेता है। दो कोड लेखक हैं: कॉल करने वाले व्यक्ति और कैली लिखने वाले व्यक्ति । कैली के लेखक ने विधि को एक आधार बना लिया है। वस्तु के बारे में दो लेखक क्या मान सकते हैं?

कुछ भी तो नहीं। कैली स्वतंत्र रूप से कास्ट को हटाने और ऑब्जेक्ट को म्यूट करने के लिए स्वतंत्र है, इसलिए कॉलर को कोई गारंटी नहीं है कि एक विधि को कॉल करना जो वास्तव में एक कॉस्ट लेता है वह इसे म्यूट नहीं करेगा। इसी तरह, कैली मान नहीं सकते हैं कि ऑब्जेक्ट की सामग्री कैली की कार्रवाई के दौरान नहीं बदलेगी; कैलली , कॉन्सट ऑब्जेक्ट के नॉन कॉस्ट एलियास पर कुछ उत्परिवर्तन विधि कह सकता है , और अब तथाकथित कॉन्स ऑब्जेक्ट बदल गया है

सी-स्टाइल कास्ट कोई गारंटी नहीं देता है कि ऑब्जेक्ट नहीं बदलेगा, और इसलिए टूट गया है। अब, सी में पहले से ही एक कमजोर प्रकार की प्रणाली है जिसमें आप एक डबल का एक पुनर्व्याख्या कलाकारों को एक इंट में कर सकते हैं यदि आप वास्तव में चाहते हैं, तो यह आश्चर्य की बात नहीं होनी चाहिए कि इसमें कमजोर प्रकार की प्रणाली के साथ-साथ सम्मान भी है। लेकिन C # को एक अच्छी प्रकार की प्रणाली के लिए डिज़ाइन किया गया था , एक प्रकार की प्रणाली जहां आप कहते हैं कि "इस चर में एक स्ट्रिंग है" जिसमें चर वास्तव में एक स्ट्रिंग (या अशक्त) का संदर्भ होता है । हम बिल्कुल सी-स्टाइल "कॉन्स्ट" संशोधक को टाइप सिस्टम में नहीं डालना चाहते हैं क्योंकि हम नहीं चाहते हैं कि टाइप सिस्टम झूठ हो । हम चाहते हैं कि प्रकार प्रणाली मजबूत हो ताकि आप अपने कोड के बारे में सही तरीके से समझ सकें ।

सी में कास्ट एक दिशानिर्देश है ; इसका मूल रूप से मतलब है "आप इस बात को म्यूट करने की कोशिश न करने के लिए मुझ पर भरोसा कर सकते हैं"। यह प्रकार प्रणाली में नहीं होना चाहिए ; प्रकार प्रणाली में सामान उस वस्तु के बारे में एक तथ्य होना चाहिए जिसके बारे में आप तर्क कर सकते हैं, इसके उपयोग के लिए दिशानिर्देश नहीं ।

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

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

हालांकि, मैं इस बात पर जोर देता हूं कि यह सिर्फ अटकलबाजी है । हमारे पास इस तरह की सुविधा को C # के किसी भी काल्पनिक भविष्य के संस्करण में डालने की कोई ठोस योजना नहीं है, अगर यहां तक ​​कि एक भी है, जिसे हमने एक या दूसरे तरीके से घोषित नहीं किया है। यह कुछ ऐसा है जिसे मैं देखना पसंद करूंगा, और कुछ ऐसा जो मल्टी-कोर कंप्यूटिंग पर आने वाले जोर की आवश्यकता हो सकती है, लेकिन इसमें से किसी को भी किसी भी तरह की भविष्यवाणी या सी # के लिए किसी विशेष सुविधा या भविष्य की दिशा की गारंटी नहीं माना जाना चाहिए।

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


34
क्षमा करें, लेकिन मुझे यह तर्क बहुत कमजोर लगता है, यह तथ्य कि एक डेवलपर कह सकता है कि किसी भी भाषा में झूठ को रोका नहीं जा सकता है। void foo (const A & a) जो ऑब्जेक्ट को संशोधित करता है वह int countApples (बास्केट b) से अलग नहीं है जो नाशपाती की संख्या लौटाता है। यह सिर्फ एक बग है, एक बग जो किसी भी भाषा में संकलित है।
एलेसैंड्रो टेरुज़ी

55
"कैलेली ने कास्ट को दूर करने के लिए स्वतंत्र है ..." उह्ह्ह्ह… (° _ °) यह एक बहुत उथले तर्क है जो आप यहां बना रहे हैं। केली भी बस के साथ यादृच्छिक स्मृति स्थानों लिखना शुरू करने के लिए स्वतंत्र है 0xDEADBEEF। लेकिन दोनों बहुत खराब प्रोग्रामिंग होंगे, और किसी भी आधुनिक संकलक द्वारा प्रारंभिक और मार्मिक रूप से पकड़े जाएंगे । भविष्य में जब उत्तर लिखते हैं, तो कृपया भ्रमित न करें कि किसी भाषा के बैकडोर का उपयोग करके तकनीकी रूप से क्या संभव है वास्तविक वास्तविक दुनिया कोड में संभव है। इस तरह की तिरछी जानकारी कम अनुभवी पाठकों को भ्रमित करती है, और SO पर जानकारी की गुणवत्ता को ख़राब करती है।
स्लिप डी। थॉम्पसन

8
"सी में कास्ट एक दिशानिर्देश है;" आप कह रहे हैं कि कुछ चीजों के लिए एक स्रोत का हवाला देते हुए वास्तव में यहाँ आपके मामले में मदद मिलेगी। मेरी शिक्षा और उद्योग के अनुभव में उद्धृत कथन हॉगवॉश है- C में कास्ट अनिवार्य रूप से निर्मित फीचर की तरह है जैसा कि टाइप सिस्टम के रूप में है- दोनों को आवश्यक होने पर उन्हें धोखा देने के लिए बैक-डोर होते हैं (जैसे कि वास्तव में C में सब कुछ है) लेकिन अपेक्षित हैं 99.99% कोड में पुस्तक द्वारा उपयोग किया जाना है।
स्लिप डी। थॉम्पसन

29
यह उत्तर यही कारण है कि मुझे कभी-कभी C # डिज़ाइन से नफरत है। भाषा डिजाइनर पूरी तरह से सुनिश्चित करते हैं कि वे अन्य डेवलपर्स की तुलना में बहुत अधिक स्मार्ट हैं और उन्हें कीड़े से अत्यधिक बचाने की कोशिश करते हैं। यह स्पष्ट रूप से है कि कॉन्स्ट कीवर्ड केवल कंपाइल-टाइम में काम करता है, क्योंकि C ++ में हम मेमोरी तक सीधी पहुंच रखते हैं और कुछ भी कर सकते हैं, जिसे हम चाहते हैं और राउंड कॉन्स्टैशन डिक्लेरेशन पाने के कई तरीके हैं। लेकिन सामान्य स्थितियों में कोई भी ऐसा नहीं करता है। वैसे, C # में 'प्राइवेट' और 'प्रोटेक्टेड' भी कोई गारंटी नहीं देते हैं, क्योंकि हम इन तरीकों या फील्ड्स पर रिफ्लेक्शन का इस्तेमाल कर सकते हैं।
BlackOverlord 15

13
@BlackOverlord: (1) एक ऐसी भाषा को डिजाइन करने की इच्छा, जिसके गुण स्वाभाविक रूप से डेवलपर्स को असफलता के बजाय सफलता की ओर ले जाते हैं , उपयोगी उपकरण बनाने की इच्छा से प्रेरित होते हैं , इस विश्वास से नहीं कि डिजाइनर आपके ग्राहकों की तुलना में होशियार हैं, जैसा कि आप अनुमान लगाते हैं। (२) परावर्तन C # भाषा का हिस्सा नहीं है; यह रनटाइम का हिस्सा है; प्रतिबिंब तक पहुंच रनटाइम की सुरक्षा प्रणाली द्वारा सीमित है। कम-विश्वास कोड को निजी प्रतिबिंब करने की क्षमता प्रदान नहीं की जाती है। गारंटी देता है पहुँच संशोधक द्वारा प्रदान के लिए कर रहे हैं कम भरोसा कोड ; उच्च विश्वास कोड कुछ भी कर सकता है।
एरिक लिपिपर्ट

24

C # में कोई कॉन्स्टिपेशन सही नहीं होने का एक कारण यह है कि यह रनटाइम स्तर पर मौजूद नहीं है। याद रखें कि C # 1.0 में तब तक कोई सुविधा नहीं थी जब तक वह रनटाइम का हिस्सा नहीं था।

और कई कारणों से CLR के पास कांस्टीट्यूशन की धारणा नहीं है, उदाहरण के लिए:

  1. यह रनटाइम को जटिल करता है; इसके अलावा, जेवीएम के पास यह भी नहीं था, और सीएलआर मूल रूप से जेवीएम जैसा रनटाइम बनाने के लिए एक परियोजना के रूप में शुरू हुआ, सी ++ की तरह - रनटाइम की तरह नहीं।
  2. यदि रनटाइम स्तर पर कांस्ट की शुद्धता है, तो BCL में कांस्ट की शुद्धता होनी चाहिए, अन्यथा जहाँ तक .NET फ्रेमवर्क का संबंध है, यह सुविधा बहुत अधिक व्यर्थ है।
  3. लेकिन अगर बीसीएल स्थिरांक शुद्धता की आवश्यकता है, CLR के शीर्ष पर हर भाषा स्थिरांक शुद्धता का समर्थन करना चाहिए (वीबी, जावास्क्रिप्ट, अजगर, रूबी, एफ #, आदि) के उस नहीं होने जा रहा।

कांस्ट की शुद्धता बहुत ज्यादा एक भाषा सुविधा है जो केवल C ++ में मौजूद है। तो यह बहुत ही तर्क के साथ उबलता है कि सीएलआर को अपवादों की जांच की आवश्यकता क्यों नहीं है (जो कि जावा भाषा-केवल सुविधा है)।

इसके अलावा, मुझे नहीं लगता कि आप पिछड़े अनुकूलता को तोड़े बिना एक प्रबंधित वातावरण में इस तरह के मौलिक प्रकार के सिस्टम फीचर को पेश कर सकते हैं। तो कभी भी C # दुनिया में प्रवेश करने वाले कांस्ट शुद्धता पर भरोसा नहीं करते।


क्या आप सुनिश्चित हैं कि जेवीएम के पास यह नहीं है। जैसा कि मुझे पता है कि यह है। आप जावा में सार्वजनिक स्थैतिक शून्य टेस्टमेथोड (अंतिम इंट वैल) की कोशिश कर सकते हैं।
इनकॉग्निटो

2
फाइनल वास्तव में कास्ट नहीं है। आप अभी भी संदर्भ IIRC पर फ़ील्ड बदल सकते हैं, न कि केवल मान / संदर्भ। (जो वैसे भी मूल्य से पारित किया जाता है, इसलिए यह पैरामीटर मान को बदलने से रोकने के लिए एक संकलक चाल है।)
रूबेन

1
आपकी तीसरी बुलेट केवल आंशिक रूप से सच है। बीसीएल कॉल के लिए कास्ट पैरामीटर होने से ब्रेकिंग परिवर्तन नहीं होगा क्योंकि वे केवल अनुबंध का अधिक सटीक वर्णन करते हैं। "यह विधि वस्तु की स्थिति को नहीं बदलेगी" इसके विपरीत "इस विधि के लिए आपको एक कॉस्ट वैल्यू पास करने की आवश्यकता होती है" जो कि ब्रेकिंग होगी
रून एफएस

2
इसे विधि के अंदर लागू किया जाता है , इसलिए इसे BCL में पेश करना एक परिवर्तन नहीं होगा।
रून एफएस

1
यहां तक ​​कि अगर रन-टाइम इसे लागू नहीं कर सकता है, तो यह एक विशेषता के लिए उपयोगी होगा जो निर्दिष्ट करता है कि क्या फ़ंक्शन को refपैरामीटर (विशेष रूप से, संरचनात्मक विधियों / गुणों के मामले में this) को लिखने की अनुमति दी जानी चाहिए । यदि कोई विधि विशेष रूप से बताती है कि यह किसी refपैरामीटर को नहीं लिखेगा , तो कंपाइलर को केवल-पढ़ने के लिए मानों को पारित करने की अनुमति देनी चाहिए। इसके विपरीत, यदि कोई विधि बताती है कि वह लिखेगा this, तो संकलक को ऐसी विधि को केवल-पढ़ने के लिए मूल्यों पर लागू करने की अनुमति नहीं देनी चाहिए।
सुपरकैट

12

मेरा मानना ​​है कि C # सही नहीं होने के दो कारण हैं।

पहली समझ है । कुछ C ++ प्रोग्रामर कॉन्स्टीट्यूशन को सही मानते हैं। का सरल उदाहरण const int argप्यारा है, लेकिन मैंने यह भी देखा है char * const * const arg- निरंतर पॉइंटर्स से लेकर गैर-निरंतर वर्णों तक एक निरंतर सूचक। कार्यों के लिए संकेत पर निरंतरता एक पूरे नए स्तर की आपत्ति है।

दूसरा है क्योंकि वर्ग तर्क मान द्वारा पारित संदर्भ हैं। इसका मतलब यह है कि स्पष्ट रूप से स्पष्ट वाक्यविन्यास के बिना, कब्ज़ से निपटने के लिए पहले से ही दो स्तर हैं । एक समान ठोकर बिंदु संग्रह (और संग्रह का संग्रह, आदि) है।

कॉन्स्ट-करेन्सी C ++ टाइप सिस्टम का एक महत्वपूर्ण हिस्सा है। यह सिद्धांत में - C # में जोड़ा जा सकता है क्योंकि कुछ ऐसा है जो केवल संकलन-समय पर जांचा जाता है (इसे सीएलआर में जोड़ने की आवश्यकता नहीं है, और बीसीएल को तब तक प्रभावित नहीं करेगा जब तक कि कास्ट सदस्य विधियों की धारणा शामिल नहीं हो जाती) ।

हालांकि, मेरा मानना ​​है कि यह संभावना नहीं है: दूसरा कारण (वाक्यविन्यास) को हल करना काफी मुश्किल होगा, जो पहले कारण (समझ) को एक समस्या का और भी अधिक बना देगा।


1
आप रहे हों तो सही है कि CLR वास्तव में, इस बारे में चिंता करने की जरूरत नहीं है के रूप में उपयोग कर सकते हैं modoptऔर modreqमेटाडाटा स्तर पर है कि जानकारी स्टोर करने के लिए (के रूप में सी + / CLI पहले से ही है - देखें System.Runtime.CompilerServices.IsConst); और यह तुच्छ तरीके से कास्ट तरीकों के लिए भी बढ़ाया जा सकता है।
पावेल मिनावे

यह सार्थक है लेकिन इसे एक प्रकार से करने की आवश्यकता है। आपके द्वारा उल्लेखित डीप / शॉलो कास्ट कीड़े के पूरे कैन को खोलता है।
user1496062

एक c ++ में जहां संदर्भ वास्तव में हेरफेर किए जाते हैं, मैं आपके तर्क को दो प्रकार के कॉन्स्टेंस के बारे में देख सकता हूं। हालाँकि, C # (जहाँ आपको "पॉइंटर्स" का उपयोग करने के लिए पिछले दरवाज़ों से गुज़रना पड़ता है) यह मेरे लिए पर्याप्त स्पष्ट है कि संदर्भ प्रकारों के लिए एक अच्छी तरह से परिभाषित अर्थ है (जैसे कि कक्षाएं) और एक अच्छी तरह से परिभाषित मूल्य के लिए अलग-अलग अर्थ। प्रकार (यानी पुरातन, structs)
Assimilater

2
प्रोग्रामर जो कॉन्स्ट-नेस को नहीं समझ सकते, उन्हें C ++ में प्रोग्रामिंग नहीं करनी चाहिए।
स्टीव व्हाइट ने

5

constC # में "संकलन-समय स्थिर" का अर्थ है, C ++ की तरह "आसानी से लेकिन संभवतः अन्य कोड द्वारा उत्परिवर्तित नहीं"। constC # का C में एक मोटा एनालॉग है readonly, लेकिन यह केवल फ़ील्ड पर लागू होता है। इसके अलावा, कोई C ++ नहीं है - जैसे C # में कॉन्स्टिपेशन सही होने की धारणा।

औचित्य सुनिश्चित करने के लिए कठिन है, क्योंकि कई संभावित कारण हैं, लेकिन मेरा अनुमान है कि भाषा को पहले और सबसे सरल रखने की इच्छा होगी, और इस दूसरे को लागू करने के अनिश्चित फायदे।


तो आपको लगता है कि एमएस 'शोर' की तरह मानता है कि विधियों में कॉन्स्ट पैरामीटर हैं।
इनकॉग्निटो

1
मुझे यकीन नहीं है कि "शोर" क्या है - मैं इसे "उच्च लागत / लाभ अनुपात" कहूंगा। लेकिन, निश्चित रूप से, आपको सी # टीम से किसी की आवश्यकता होगी ताकि आप सुनिश्चित कर सकें।
पावेल मिनेव

इसलिए जैसा कि मैं इसे समझता हूं, आपका तर्क यह है कि कब्ज को सरल रखने के लिए C # छोड़ दिया गया था। उसके बारे में सोचना।
स्टीव व्हाइट ने

2

यह C # 7.2 (दृश्य स्टूडियो 2017 15.5 के साथ दिसंबर 2017) के बाद से संभव है।

केवल संरचनाओं और बुनियादी प्रकारों के लिए ! वर्गों के सदस्यों के लिए नहीं।

आपको inसंदर्भ द्वारा इनपुट के रूप में तर्क भेजने के लिए उपयोग करना चाहिए । देख:

देखें: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier

अपने उदाहरण के लिए:

....
static void TestMethod1(in MyStruct val)
{
    val = new MyStruct;  // Error CS8331 Cannot assign to variable 'in MyStruct' because it is a readonly variable
    val.member = 0;  // Error CS8332 Cannot assign to a member of variable 'MyStruct' because it is a readonly variable
}
....
static void TestMethod2(in int val)
{
    val = 0;  // Error CS8331 Cannot assign to variable 'in int' because it is a readonly variable
}
....
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.