2009-01-14 16 views
26

कंपाइलर त्रुटि CS0283 इंगित करता है कि केवल मूल पीओडी प्रकार (साथ ही तार, enums, और शून्य संदर्भ) const के रूप में घोषित किया जा सकता है। क्या किसी के पास इस सीमा के लिए तर्क पर सिद्धांत है? उदाहरण के लिए, इंटिप्ट जैसे अन्य प्रकार के कॉन्स वैल्यू घोषित करने में सक्षम होना अच्छा होगा।सी # उन प्रकारों के सेट को सीमित क्यों करता है जिन्हें कॉन्स्ट के रूप में घोषित किया जा सकता है?

मेरा मानना ​​है कि const की अवधारणा वास्तव में सी # में वाक्य रचनात्मक चीनी है, और यह केवल शाब्दिक मूल्य के साथ नाम के किसी भी उपयोग को प्रतिस्थापित करती है। उदाहरण के लिए, निम्नलिखित घोषणा दी गई है, फू के किसी भी संदर्भ को संकलन समय पर "foo" के साथ प्रतिस्थापित किया जाएगा।

const string Foo = "foo"; 

यह किसी भी परिवर्तनशील प्रकार से इनकार करेगा, तो शायद वे संकलन समय हैं कि कोई प्रकार परिवर्तनशील है पर यह निर्धारित करने के लिए होने के बजाय इस सीमा चुना?

उत्तर

26

C# specification, chapter 10.4 - Constants से: जो कर सकते हैं एक मूल्य:
(सी # 3.0 विनिर्देश में 10.4, 10.3 2.0 के लिए ऑनलाइन संस्करण में)

एक निरंतर एक वर्ग के सदस्य है कि एक निरंतर मूल्य का प्रतिनिधित्व करता है संकलन समय पर गणना कीजिए।

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

IntPtr, एक उदाहरण के रूप में, एक मूल्य प्रकार होने के बावजूद, अभी भी एक संरचना है, और अंतर्निहित अक्षरों में से एक नहीं है। इस प्रकार, इंटप्राट का उपयोग करने वाली किसी भी अभिव्यक्ति को इंटिप्ट संरचना में कोड कॉल करने की आवश्यकता होगी, और यह निरंतर घोषणा के लिए कानूनी नहीं है।

एकमात्र कानूनी निरंतर मूल्य प्रकार उदाहरण मैं सोच सकता हूं कि शून्य के साथ इसे घोषित करके शुरू किया जाएगा, और यह शायद ही उपयोगी है।

कंपाइलर कैसे स्थिरांक का उपयोग/उपयोग करता है, यह कोड में निरंतर नाम के स्थान पर गणना मूल्य का उपयोग करेगा।

इस प्रकार, आप निम्नलिखित प्रभाव है:

  • मूल निरंतर नाम करने के लिए कोई संदर्भ, वर्ग उस में घोषित किया गया था, या नाम स्थान, इस स्थान
  • में कोड में संकलित किया गया है आप डिकंपाइल हैं कोड में, इसमें जादू संख्याएं होंगी, क्योंकि केवल ऊपर वर्णित मूल "संदर्भ" है, वर्तमान में नहीं, केवल
  • का मान संकलक इसे अनुकूलित करने या यहां तक ​​कि निकालने के लिए उपयोग कर सकता है, अनावश्यक कोड उदाहरण के लिए, if (SomeClass.Version == 1), जब SomeClass.Version का मान 1 है, वास्तव में if-statement को हटा देगा, और कोड के ब्लॉक को निष्पादित किया जाएगा। यदि स्थिरांक का मान 1 नहीं है, तो संपूर्ण if-statement और उसका ब्लॉक हटा दिया जाएगा।
  • चूंकि निरंतर के मान को कोड में संकलित किया गया है, और निरंतर संदर्भ नहीं है, अन्य असेंबली से स्थिरांक का उपयोग करके संकलित कोड को किसी भी तरह से स्वचालित रूप से अपडेट नहीं किया जाएगा यदि स्थिरता का मूल्य बदलना चाहिए (जिसे इसे करना चाहिए नहीं)

दूसरे शब्दों में, इस परिदृश्य के साथ:

  1. विधानसभा ए, "संस्करण" नाम के एक निरंतर, 1
  2. विधानसभा बी के एक मूल्य के लिए होने शामिल है, एक अभिव्यक्ति है, जो उस निरंतर ए से असेंबली ए के संस्करण संख्या का विश्लेषण करता है nd यह 1 की तुलना में, 2 के लिए निरंतर की कीमत बढ़ यकीन है कि यह विधानसभा
  3. किसी को संशोधित करता विधानसभा एक साथ काम कर सकते बनाने के लिए, और पुनर्निर्माण एक (लेकिन बी)

इस मामले में, असेंबली बी, इसके संकलित रूप में, अभी भी 1 से 1 के मान की तुलना करेगा, क्योंकि जब बी संकलित किया गया था, तो स्थिरांक का मूल्य 1.

वास्तव में, यदि यह असेंबली ए से कुछ भी उपयोग है असेंबली बी, असेंबली बी को असेंबली ए पर निर्भरता के बिना संकलित किया जाएगा। असेंबली बी में उस अभिव्यक्ति वाले कोड को निष्पादित करना असेंबली ए लोड नहीं करेगा।

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

तो यह ठीक है:

  • सार्वजनिक स्थिरांक Int32 NumberOfDaysInAWeekInGregorianCalendar = 7;
  • सार्वजनिक कॉन्स Int32 NumberOfHoursInADayOnEarth = 24;

इस जबकि नहीं है:

  • सार्वजनिक स्थिरांक Int32 AgeOfProgrammer = 25;
  • सार्वजनिक कॉन्स स्ट्रिंग नामऑफलास्टप्रोग्रामरैटमोडिफाइडएस्क्रिप्ट्स = "जो प्रोग्रामर";

संपादित कर सकते हैं 27 वें वर्ष 2016

ठीक है, सिर्फ एक वोट दें मिला है, इसलिए मैं अपने जवाब यहाँ फिर से पढ़ सकते हैं और यह वास्तव में थोड़ा गलत है।

अब, सी # भाषा विनिर्देश के इरादे सब कुछ मैंने ऊपर लिखा है। आपको ऐसा कुछ उपयोग नहीं करना चाहिए जिसे const के रूप में शाब्दिक के साथ प्रदर्शित नहीं किया जा सकता है।

लेकिन क्या आप कर सकते हैं? खैर, हाँ ....

चलो decimal प्रकार पर एक नज़र डालें।

.field public static initonly valuetype [mscorlib]System.Decimal X 
.custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(int8, uint8, uint32, uint32, uint32) = (01 00 01 00 00 00 00 00 00 00 00 00 64 00 00 00 00 00) 

मुझे यह आप के लिए तोड़ने के नीचे दो::

.field public static initonly 

से मेल खाती है:

public class Test 
{ 
    public const decimal Value = 10.123M; 
} 

के इस वर्ग के वास्तव में जब ILDASM साथ को देखा कैसा दिखता है पर नजर डालते हैं

public static readonly 

यह सही है, const decimal वास्तव में readonly decimal है।

असली सौदा यह है कि संकलक DecimalConstantAttribute का उपयोग अपने जादू के लिए करेगा।

अब, यह एकमात्र ऐसा जादू है जिसे मैं सी # कंपाइलर के साथ जानता हूं लेकिन मैंने सोचा कि यह उल्लेखनीय है।

+1

जाहिर है आप यह नहीं कर सकते हैं लेकिन * hypothetically बोलते हुए *, कहते हैं कि हमारे पास एक मूल्य-प्रकार-लौटने वाली स्थिर विधि थी जिसे [शुद्ध] विशेषता के साथ चिह्नित किया गया था और संकलक वास्तव में इसे लागू करता है (यह वर्तमान में नहीं है)। क्या भाषा डिजाइनर कम से कम * सैद्धांतिक रूप से * स्थिर मूल्य-प्रकार-लौटने वाली शुद्ध विधि (वास्तविक [शुद्ध] विशेषता प्रवर्तन के साथ) को तब तक शुरू कर सकते हैं जब तक कि तर्क कुछ भी नहीं बल्कि शाब्दिक थे? ऐसा लगता है कि वे इसे शाब्दिक तर्कों के साथ चला सकते हैं, परिणाम प्राप्त करें जो स्पष्ट रूप से बदलने के लिए नहीं जा रहा है और मूल्य में उप है। क्या मैं कुछ देख रहा हूँ? –

+0

'इस मामले में, असेंबली बी, इसके संकलित रूप में, अभी भी 1 से 1 के मान की तुलना करेगा, क्योंकि जब बी संकलित किया गया था, तो निरंतर मान 1 था - आप अभी भी वही चीज़ कर सकते हैं जो' सार्वजनिक आधार int विधानसभा संस्करण = 1' आज किसी भी सी # संस्करण में, इसलिए संरचनाओं के साथ कुछ भी गलत नहीं है * खुद –

1

मुझे विश्वास है कि स्थिरांक की अवधारणा वास्तव में सी # में वाक्यात्मक चीनी है, और यह सिर्फ शाब्दिक मूल्य

क्या संकलक करता है के साथ नाम के किसी भी उपयोग करता है की जगह है कि अन्य में स्थिरांक वस्तुओं के साथ क्या भाषाओं?

आप म्यूटेबल प्रकारों के लिए केवल पढ़ने के लिए उपयोग कर सकते हैं जिनका मुझे रनटाइम पर मूल्यांकन किया जा सकता है। मतभेदों के लिए this article देखें।

+0

मुझे लगता है कि आप इसे प्रतिबिंबक का उपयोग करके देख सकते हैं। – BuddyJoe

+0

कीवर्ड कास्ट अलग-अलग भाषाओं में अलग-अलग प्रभाव डाल सकता है, जैसे सी ++ में, जहां इसका उपयोग यह गारंटी करने के लिए किया जा सकता है कि एक विधि किसी ऑब्जेक्ट की स्थिति को किसी उदाहरण के रूप में नहीं बदलती है। –

+0

@ LasseV.Karlsen, लेकिन 'const' का अर्थ सी (++) और सी # दोनों में गैर-संदर्भ * प्रकारों के लिए समान है। तो इस जवाब के बारे में बात करते समय यह जवाब सही है। अन्य भाषाओं में "कॉन्स्ट शुद्धता" की यह अवधारणा है। सी # में सबसे नज़दीकी एनालॉग अपरिवर्तनीय पैटर्न है जिसे कन्स्ट्रक्टर द्वारा शुरू किए गए 'रीडोनली' क्लास सदस्यों के साथ जोड़ा जाता है। – binki

0

कॉन्स सी # में संख्याओं और तारों तक ही सीमित हैं क्योंकि संकलक एमएसआईएल में शाब्दिक मूल्य के साथ परिवर्तनीय को प्रतिस्थापित करता है। दूसरे शब्दों में, जब आप लिखते हैं:

const string myName = "Bruce Wayne"; 
if (someVar == myName) 
{ 
    ... 
} 

वास्तव में

if (someVar == "Bruce Wayne") 
{ 
    ... 
} 

के रूप में व्यवहार किया जाता है और हाँ, सी # संकलक बहुत चालाक

string1.Equals(string2) 
के रूप में तारों पर समानता ऑपरेटर (==) के इलाज के लिए है
+0

ठीक है, मुझे नहीं मिलता है कि आप क्यों घोषित नहीं कर सके एक कॉन्स IntPtr, जिसे उपयोग बिंदुओं पर भी बदला जा सकता है। शायद अंतर यह है कि एक इंटीपीआरआर का निर्माण करना होगा, जबकि पीओडी और स्ट्रिंग सीधे आईएल में प्रदर्शित किए जा सकते हैं। – Charlie

+0

अंतिम मूल्य प्राप्त करने के लिए कंपाइलर को IntPtr में कोड निष्पादित करना होगा, और यह "मान प्राप्त करने के लिए कोड निष्पादित करें" भाग को जहां भी निरंतर उपयोग किया जाता है, कोड में संकलित करना होगा, और यह वह हिस्सा है जिसकी अनुमति नहीं है । –

1

क्या किसी के पास इस सीमा के लिए तर्क पर कोई सिद्धांत है?

यह सिर्फ एक सिद्धांत होने की अनुमति देता तो मेरी सिद्धांत यह है कि आदिम प्रकार की स्थिरांक मान MSIL में शाब्दिक opcode मापदंडों पर व्यक्त किया जा सकता है ... लेकिन अन्य, गैर-प्राथमिक प्रकारों की नहीं कर सकते हैं क्योंकि एमएसआईएल में उपयोगकर्ता द्वारा परिभाषित प्रकार के मूल्य को शाब्दिक के रूप में व्यक्त करने के लिए वाक्यविन्यास नहीं है।

+0

ऐसा लगता है, हाँ (@IAmCodeMonkey पर भी मेरी टिप्पणी देखें) – Charlie

+0

एमएसआईएल बाइट्स के अनुक्रम के संदर्भ में स्थिरांक परिभाषित करता है। उदाहरण के प्रकार को देखते हुए उदा। 'संरचना वेक्टर 2 डी {सार्वजनिक डबल एक्स, वाई;}', एक कंपाइलर स्थिर 'कॉन्स्ट वेक्टर 2 डी यूनिटएक्स वेक्टर = {एक्स = 1.0, वाई = 0.0} की घोषणा की अनुमति दे सकता है;', क्योंकि यह उस बाइट्स के सटीक अनुक्रम को निर्धारित कर सकता है संरचना। यह केवल एक निजी क्षेत्र के साथ एक संरचना के लिए काम करेगा; यदि कोई संरचना सार्वजनिक गुणों और निजी बैकिंग फ़ील्ड का उपयोग करती है, तो एक कंपाइलर केवल यह पता लगाकर बना सकता है कि वास्तव में गुण क्या हैं। – supercat

+0

@supercat, क्या आप यह कह रहे हैं कि एमएसआईएल वस्तुओं पर निर्भर करता है कि स्मृति में एक निश्चित तरीके से क्या किया जा रहा है? ['StructLayoutAttribute'] का अस्तित्व नहीं है (https://msdn.microsoft.com/en-us/library/System.Runtime.InteropServices.StructLayoutAttribute%28v=vs.100%29.aspx) का अर्थ है कि यह ' टी? – binki

0

ऐसा लगता है कि केवल मूल्य प्रकार स्थिर के रूप में व्यक्त किए जा सकते हैं (तारों के अपवाद के साथ, जो मूल्य और वस्तु प्रकार के बीच कहीं भी खड़ा होता है)।

यह मेरे लिए ठीक है: वस्तुओं (संदर्भ) को ढेर पर आवंटित किया जाना चाहिए लेकिन स्थिरांक आवंटित नहीं किए जाते हैं (क्योंकि उन्हें संकलन समय पर प्रतिस्थापित किया जाता है)।

+1

स्ट्रिंग का उपयोग किया जा सकता है क्योंकि संकलक किसी दिए गए मान के साथ स्ट्रिंग लोड करने के लिए आईएल कोड डाल सकता है। चूंकि यह आईएल जादू विशेष रूप से तारों के लिए जोड़ा गया है, इसलिए उनका उपयोग किया जा सकता है। –

0

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

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

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