C # 3.0 ऑब्जेक्ट इनिशियलाइज़र कंस्ट्रक्टर कोष्ठक वैकल्पिक क्यों हैं?


114

ऐसा लगता है कि सी # 3.0 ऑब्जेक्ट इनिशियलाइज़र सिंटेक्स एक को कंस्ट्रक्टर में पैरेंटेस के खुले / करीबी जोड़े को बाहर करने की अनुमति देता है जब कोई पैरामीटर रहित कंस्ट्रक्टर विद्यमान होता है। उदाहरण:

var x = new XTypeName { PropA = value, PropB = value };

विरोध के रूप में:

var x = new XTypeName() { PropA = value, PropB = value };

मैं उत्सुक हूं कि कंस्ट्रक्टर ओपन / क्लोज कोष्ठक जोड़ी यहां के बाद वैकल्पिक XTypeNameक्यों है?


9
एक तरफ के रूप में, हमने पिछले सप्ताह एक कोड समीक्षा में यह पाया: var सूची = नई सूची <Foo> {}; अगर किसी चीज का दुरुपयोग किया जा सकता है ...
blu

@ बब्लू यही एक कारण है कि मैं यह सवाल पूछना चाहता था। मैंने हमारे कोड में असंगति पर ध्यान दिया। सामान्य रूप से असंगतता मुझे परेशान करती है इसलिए मैंने सोचा कि अगर सिंटैक्स में वैकल्पिकता के पीछे एक अच्छा तर्क है तो मैं देखूंगा। :)
जेम्स ड्यूने

जवाबों:


143

यह प्रश्न २० सितंबर २०१० को मेरे ब्लॉग का विषय था । जोश और चाड के जवाब ("वे कोई मूल्य नहीं जोड़ते हैं, इसलिए उनकी आवश्यकता क्यों है?" और "अतिरेक को खत्म करने के लिए") मूल रूप से सही हैं। मांस को थोड़ा और अधिक:

ऑब्जेक्ट इनिशियलाइज़र्स की "बड़ी विशेषता" के भाग के रूप में आपको तर्क सूची को खत्म करने की अनुमति देने की सुविधा "शर्करा" सुविधाओं के लिए हमारे बार से मिली। कुछ बिंदुओं पर हमने विचार किया:

  • डिजाइन और विनिर्देश लागत कम थी
  • हम बड़े पैमाने पर पार्सर कोड को बदलने जा रहे थे जो वैसे भी ऑब्जेक्ट निर्माण को संभालता है; बड़ी सूची की लागत की तुलना में पैरामीटर सूची को वैकल्पिक बनाने की अतिरिक्त विकास लागत बड़ी नहीं थी
  • बड़ी सुविधा की लागत की तुलना में परीक्षण का बोझ अपेक्षाकृत छोटा था
  • प्रलेखन बोझ अपेक्षाकृत छोटा था ...
  • रखरखाव का बोझ छोटा होने का अनुमान था; मुझे इस सुविधा में रिपोर्ट किए गए वर्षों के बाद से कोई भी बग याद नहीं है।
  • इस क्षेत्र में भविष्य की सुविधाओं के लिए कोई भी तुरंत स्पष्ट जोखिम नहीं है। (आखिरी चीज जो हम करना चाहते हैं वह अब एक सस्ता, आसान फीचर है जो भविष्य में एक अधिक सम्मोहक सुविधा को लागू करने के लिए बहुत कठिन बनाता है।)
  • यह सुविधा भाषा के शाब्दिक, व्याकरणिक या अर्थ विश्लेषण के लिए कोई नई अस्पष्टता नहीं जोड़ती है। यह "आंशिक कार्यक्रम" विश्लेषण के प्रकार के लिए कोई समस्या नहीं है जो IDE के "IntelliSense" इंजन द्वारा टाइप किए जाने के दौरान किया जाता है। और इसी तरह।
  • सुविधा बड़ी वस्तु इनिशियलाइज़ेशन फ़ीचर के लिए एक सामान्य "स्वीट स्पॉट" को हिट करती है; आम तौर पर यदि आप किसी ऑब्जेक्ट इनिलाइज़र का उपयोग कर रहे हैं तो यह ठीक है क्योंकि ऑब्जेक्ट का निर्माता आपको आपके इच्छित गुणों को सेट करने की अनुमति नहीं देता है। ऐसी वस्तुओं के लिए बस "प्रॉपर्टी बैग" होना बहुत ही आम बात है, जो पहले स्थान पर ctor में कोई पैरामीटर नहीं है।

तब आपने ऑब्जेक्ट निर्माण अभिव्यक्ति के डिफ़ॉल्ट कंस्ट्रक्टर कॉल में खाली कोष्ठक को वैकल्पिक क्यों नहीं बनाया , जिसमें ऑब्जेक्ट इनिशियलाइज़र नहीं है?

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

class P
{
    class B
    {
        public class M { }
    }
    class C : B
    {
        new public void M(){}
    }
    static void Main()
    {
        new C().M(); // 1
        new C.M();   // 2
    }
}

पंक्ति 1 एक नया C बनाता है, डिफ़ॉल्ट कंस्ट्रक्टर को कॉल करता है, और फिर नई ऑब्जेक्ट पर इंस्टेंस विधि M को कॉल करता है। लाइन 2 बीएम का एक नया उदाहरण बनाता है और अपने डिफ़ॉल्ट निर्माता को कॉल करता है। यदि पंक्ति 1 पर कोष्ठक वैकल्पिक थे तो पंक्ति 2 अस्पष्ट होगी। फिर हमें अस्पष्टता को हल करने वाले नियम के साथ आना होगा; हम इसे एक त्रुटि नहीं बना सकते क्योंकि यह एक ब्रेकिंग परिवर्तन होगा जो मौजूदा कानूनी C # प्रोग्राम को एक टूटे हुए प्रोग्राम में बदलता है।

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

उस प्रकाश में, वापस जाएं और मेरे द्वारा उल्लिखित सभी लागतों को देखें। उनमें से कितने अब बड़े हो गए हैं? जटिल नियमों में बड़े डिजाइन, कल्पना, विकास, परीक्षण और प्रलेखन लागत हैं। भविष्य में सुविधाओं के साथ अनपेक्षित बातचीत के साथ जटिल नियम समस्याओं का कारण बन सकते हैं।

सभी के लिए क्या? एक छोटा ग्राहक लाभ, जो भाषा में कोई नई प्रतिनिधित्वात्मक शक्ति नहीं जोड़ता है, लेकिन पागल कोने के मामलों को जोड़ देता है, जो "ग़ाचा" की प्रतीक्षा कर रहे हैं, जो कुछ गरीब असंतुष्ट आत्मा पर चलता है। इस तरह की सुविधाएँ तुरंत कट जाती हैं और "कभी नहीं करें" सूची में डाल दी जाती हैं।

आपने उस विशेष अस्पष्टता का निर्धारण कैसे किया?

वह एक तुरंत स्पष्ट था; जब एक बिंदीदार नाम की उम्मीद की जाती है, तो यह निर्धारित करने के लिए मैं सी # में नियमों से बहुत परिचित हूं।

एक नई सुविधा पर विचार करते समय आप कैसे निर्धारित करते हैं कि यह किसी भी अस्पष्टता का कारण बनता है? हाथ से, औपचारिक प्रमाण से, मशीन विश्लेषण से, क्या?

सभी तीन। ज्यादातर हम सिर्फ कल्पना और उस पर नूडल देखते हैं, जैसा कि मैंने ऊपर किया था। उदाहरण के लिए, मान लें कि हम एक नए उपसर्ग ऑपरेटर को C # में जोड़ना चाहते थे जिसे "फ्रोब" कहा जाता है:

x = frob 123 + 456;

(अद्यतन: frobनिश्चित रूप से await, यहाँ विश्लेषण अनिवार्य रूप से विश्लेषण है कि डिजाइन टीम को जोड़ते समय हुआ था await।)

"फ्रोब" यहां "नया" या "++" जैसा है - यह किसी प्रकार की अभिव्यक्ति से पहले आता है। हम वांछित वरीयता और सहानुभूति और इतने पर काम करेंगे, और फिर सवाल पूछना शुरू कर देंगे "क्या होगा यदि कार्यक्रम में पहले से ही एक प्रकार, क्षेत्र, संपत्ति, घटना, विधि, निरंतर, या स्थानीय कहा जाता है?" यह तुरंत मामलों की ओर ले जाएगा जैसे:

frob x = 10;

क्या इसका मतलब यह है कि "x = 10 के परिणाम पर फ्रोब ऑपरेशन करें, या x नामक प्रकार के फ्रोब का एक वैरिएबल बनाएं और उसमें 10 को असाइन करें?" (या, अगर फ्रोबिंग एक चर का उत्पादन करता है, तो यह 10 से एक असाइनमेंट हो सकता है frob x। सब के बाद, *x = 10;पर्स और कानूनी है अगर xहै int*।)

G(frob + x)

इसका मतलब है कि "एक्स पर यूनिरी प्लस ऑपरेटर का परिणाम" या "एक्सप्रेशन फ़्राब को एक्स" में जोड़ें?

और इसी तरह। इन अस्पष्टताओं को हल करने के लिए हम उत्तराधिकार का परिचय दे सकते हैं। जब आप कहते हैं "var x = 10;" वह अस्पष्ट है; इसका अर्थ "एक्स के प्रकार का अनुमान लगाना" हो सकता है या इसका मतलब "एक्स प्रकार का है" हो सकता है। इसलिए हमारे पास एक अनुमान है: हम पहले एक प्रकार का नाम देखने का प्रयास करते हैं, और केवल अगर कोई मौजूद नहीं है तो हम एक्स के प्रकार का अनुमान लगाते हैं।

या, हम वाक्यविन्यास को बदल सकते हैं ताकि यह अस्पष्ट न हो। जब उन्होंने C # 2.0 डिज़ाइन किया तो उन्हें यह समस्या हुई:

yield(x);

क्या इसका मतलब है "पैदावार x को एक पुनरावृत्त में" या "तर्क एक्स के साथ उपज विधि को बुलाओ?" इसे बदलकर

yield return(x);

यह अब असंदिग्ध है।

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

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

या, जब हमने C # 3.0 में लैम्ब्डा पर उन्नत प्रकार की आक्षेप किया, तो हमने अपने प्रस्ताव लिखे और फिर उन्हें कैम्ब्रिज में माइक्रोसॉफ्ट रिसर्च के तालाब पर भेज दिया, जहाँ भाषाओं की टीम ने एक औपचारिक प्रमाण तैयार करने के लिए काफी अच्छा था कि प्रकार का प्रस्ताव। सैद्धांतिक रूप से ध्वनि।

क्या आज C # में अस्पष्टताएँ हैं?

ज़रूर।

G(F<A, B>(0))

C # 1 में यह स्पष्ट है कि इसका क्या मतलब है। यह समान है:

G( (F<A), (B>0) )

यही है, यह जी को दो तर्कों के साथ बुलाता है जो बूल हैं। C # 2 में, इसका मतलब यह हो सकता है कि C # 1 में इसका क्या अर्थ है, लेकिन इसका मतलब यह भी हो सकता है "सामान्य विधि F के पास 0 जो टाइप पैरामीटर A और B लेता है, और फिर F से G के परिणाम को पास करें"। हमने पार्सर में एक जटिल हेयूरिस्टिक जोड़ा, जो यह निर्धारित करता है कि आप में से दो मामलों का क्या मतलब है।

इसी तरह, C # 1.0 में भी कलाकार अस्पष्ट हैं:

G((T)-x)

क्या वह "कास्ट-एक्स टू टी" या "टी से एक्सट्रैक्ट एक्स" है? फिर, हमारे पास एक अनुमान है जो एक अच्छा अनुमान लगाता है।


3
ओह क्षमा करें, मैं भूल गया ... जब यह काम करने के लिए प्रकट होता है, तो बैट सिग्नल दृष्टिकोण, (IMO) संपर्क का एक सीधा साधन है, जिससे किसी को सार्वजनिक प्रदर्शन नहीं मिलेगा, ताकि वह सार्वजनिक शिक्षा के लिए SO पोस्ट के रूप में चाहता हो। अनुक्रमित, खोज योग्य है, और आसानी से संदर्भित करने में सक्षम है। इसके बजाय हम एक सीधे SO पोस्ट / उत्तर नृत्य को कोरियोग्राफ करने के लिए सीधे संपर्क करेंगे? :)
जेम्स ड्यूने

5
मेरा सुझाव है कि आप एक पोस्ट करने से बचें। यह उन लोगों के लिए उचित नहीं होगा जिनके पास प्रश्न में अतिरिक्त अंतर्दृष्टि हो सकती है। प्रश्न को पोस्ट करने के लिए एक बेहतर दृष्टिकोण होगा, फिर इसमें भाग लेने के लिए एक लिंक ईमेल करें।
चिल्लेम्प सिप

1
@ नाम: मैंने आपके अनुवर्ती प्रश्न को संबोधित करने के लिए अपना उत्तर अपडेट कर दिया है।
एरिक लिपर्ट

8
@, क्या यह संभव है कि आप इस "कभी न करें" सूची के बारे में ब्लॉग कर सकें? मैं अन्य उदाहरणों को देखने के लिए उत्सुक हूं जो कभी भी C # भाषा का हिस्सा नहीं होंगे :)
Ilya Ryzhenkov

2
@ एरिक: मैं वास्तव में वास्तव में मेरे साथ आपके धैर्य की सराहना करता हूं :) धन्यवाद! बहुत सूचनाप्रद।
जेम्स ड्यूने

12

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

यह भी अंतर्निहित टाइपेज़ सरणियों के समान है

var a = new[] { 1, 10, 100, 1000 };            // int[]
var b = new[] { 1, 1.5, 2, 2.5 };            // double[]
var c = new[] { "hello", null, "world" };      // string[]
var d = new[] { 1, "one", 2, "two" };         // Error

संदर्भ: http://msdn.microsoft.com/en-us/library/ms364047%28VS.80%29.aspx


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

1
@ जेम्स ड्यूने, यह वास्तव में समान रूप से टाइप किए गए सरणी सिंटैक्स के समान सिंटैक्स है, मेरा संपादन देखें। कोई प्रकार नहीं है, कोई निर्माता नहीं है, और इरादे स्पष्ट हैं, इसलिए इसे घोषित करने की कोई आवश्यकता नहीं है
CaffGeek

7

यह वस्तुओं के निर्माण को सरल बनाने के लिए किया गया था। भाषा डिजाइनरों ने (मेरे ज्ञान के लिए) विशेष रूप से नहीं कहा कि उन्हें क्यों लगा कि यह उपयोगी है, हालांकि यह स्पष्ट रूप से सी # संस्करण 3.0 विनिर्देश पृष्ठ में उल्लिखित है :

एक ऑब्जेक्ट क्रिएशन एक्सप्रेशन कंस्ट्रक्टर लॉजिक लिस्ट और एनकोडिंग कोष्ठक को छोड़ सकता है, बशर्ते इसमें ऑब्जेक्ट या कलेक्शन इनिशलाइज़र शामिल हो। कंस्ट्रक्टर तर्क सूची को स्वीकार करना और कोष्ठकों को संलग्न करना एक खाली तर्क सूची को निर्दिष्ट करने के बराबर है।

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


4

आपके पहले उदाहरण में, कंपाइलर इन्फ़ॉर्मर्स जिसे आप डिफॉल्ट कंस्ट्रक्टर कह रहे हैं (C # 3.0 लैंग्वेज स्पेसिफिकेशन बताता है कि यदि कोई कोष्ठक प्रदान नहीं किया गया है, तो डिफॉल्ट कंस्ट्रक्टर कहा जाता है)।

दूसरे में, आप स्पष्ट रूप से डिफ़ॉल्ट निर्माता को कॉल करते हैं।

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

public class SomeTest
{
    public string Value { get; private set; }
    public string AnotherValue { get; set; }
    public string YetAnotherValue { get; set;}

    public SomeTest() { }

    public SomeTest(string value)
    {
        Value = value;
    }
}

सभी तीन कथन मान्य हैं:

var obj = new SomeTest { AnotherValue = "Hello", YetAnotherValue = "World" };
var obj = new SomeTest() { AnotherValue = "Hello", YetAnotherValue = "World"};
var obj = new SomeTest("Hello") { AnotherValue = "World", YetAnotherValue = "!"};

सही। आपके उदाहरण में पहले और दूसरे मामले में ये कार्यात्मक रूप से समान हैं, सही हैं?
जेम्स ड्यूने

1
@ जेम्स ड्यूने - सही। वह भाषा युक्ति द्वारा निर्दिष्ट भाग है। खाली कोष्ठक बेमानी हैं, लेकिन आप अभी भी उन्हें आपूर्ति कर सकते हैं।
जस्टिन निस्नेर

1

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


ठीक है, यह बेमानी है, लेकिन मैं बस उत्सुक हूं कि उनका अचानक परिचय वैकल्पिक क्यों है? यह भाषा वाक्य रचना की संगति से टूटने लगता है। यदि मेरे पास एक प्रारंभिक ब्लॉक को इंगित करने के लिए खुले घुंघराले ब्रेस नहीं हैं, तो यह अवैध सिंटैक्स होना चाहिए। मजेदार बात कि आपने मिस्टर लिपर्ट का उल्लेख किया, मैं उनके जवाब के लिए सार्वजनिक रूप से मछली पकड़ने का काम कर रहा था ताकि खुद को और दूसरों को निष्क्रिय जिज्ञासा से फायदा हो। :)
जेम्स ड्यूने
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.