मैं .NET में एक संरचना के लिए डिफ़ॉल्ट कंस्ट्रक्टर को परिभाषित क्यों नहीं कर सकता?


261

.NET में, एक मान प्रकार (C # struct) का कोई पैरामीटर नहीं हो सकता है। इस पोस्ट के अनुसार यह सीएलआई विनिर्देश द्वारा अनिवार्य है। क्या होता है कि हर मूल्य-प्रकार के लिए एक डिफ़ॉल्ट कंस्ट्रक्टर (कंपाइलर द्वारा?) बनाया जाता है, जो सभी सदस्यों को शून्य (या null) के लिए इनिशियलाइज़ करता है ।

ऐसे डिफ़ॉल्ट कंस्ट्रक्टर को परिभाषित करने के लिए इसे क्यों अस्वीकृत किया गया है?

एक तुच्छ उपयोग तर्कसंगत संख्याओं के लिए है:

public struct Rational {
    private long numerator;
    private long denominator;

    public Rational(long num, long denom)
    { /* Todo: Find GCD etc. */ }

    public Rational(long num)
    {
        numerator = num;
        denominator = 1;
    }

    public Rational() // This is not allowed
    {
        numerator = 0;
        denominator = 1;
    }
}

C # के वर्तमान संस्करण का उपयोग करते हुए, एक डिफ़ॉल्ट तर्कसंगत 0/0जो इतना अच्छा नहीं है।

पुनश्च : क्या डिफ़ॉल्ट पैरामीटर सी # 4.0 के लिए इसे हल करने में मदद करेगा या सीएलआर-परिभाषित डिफॉल्ट कंस्ट्रक्टर कहा जाएगा?


जॉन स्कीट ने उत्तर दिया:

अपने उदाहरण का उपयोग करने के लिए, जब कोई व्यक्ति क्या करना चाहेगा:

 Rational[] fractions = new Rational[1000];

यह 1000 बार अपने निर्माता के माध्यम से चलना चाहिए?

निश्चित रूप से यह होना चाहिए, इसीलिए मैंने पहली बार में डिफॉल्ट कंस्ट्रक्टर लिखा। सीएलआर को डिफ़ॉल्ट शून्य निर्माणकर्ता का उपयोग करना चाहिए जब कोई स्पष्ट डिफ़ॉल्ट निर्माता परिभाषित नहीं होता है; इस तरह से आप केवल उसी चीज़ का भुगतान करते हैं जो आप उपयोग करते हैं। फिर अगर मुझे 1000 नॉन-डिफॉल्ट Rationals का कंटेनर चाहिए (और 1000 कंस्ट्रक्शन को दूर करना है) तो मैं List<Rational>एरे के बजाय इस्तेमाल करूंगा ।

यह कारण, मेरे दिमाग में, एक डिफ़ॉल्ट रचनाकार की परिभाषा को रोकने के लिए पर्याप्त मजबूत नहीं है।


3
+1 में एक बार समान समस्या थी, अंत में संरचना को एक वर्ग में बदल दिया।
डर्क वोल्मार

4
C # 4 में डिफ़ॉल्ट पैरामीटर मदद नहीं कर सकता क्योंकि Rational()इसके बजाय पैरामीटर रहित ctor को आमंत्रित करता है Rational(long num=0, long denom=1)
LaTeX

6
ध्यान दें कि C # 6.0 में जो विजुअल स्टूडियो 2015 के साथ आता है, उसे स्ट्रक्चर्स के लिए शून्य-पैरामीटर इंस्टेंस कंस्ट्रक्टर लिखने की अनुमति होगी। तो new Rational()अगर यह मौजूद है, तो निर्माता का आह्वान करेगा, हालांकि अगर यह मौजूद नहीं है, तो इसके new Rational()बराबर होगा default(Rational)। किसी भी स्थिति में आपको सिंटैक्स का उपयोग करने के लिए प्रोत्साहित किया जाता है default(Rational)जब आप अपनी संरचना के "शून्य मान" (जो आपके प्रस्तावित डिजाइन के साथ एक "बुरा" संख्या चाहते हैं Rational)। मान प्रकार के लिए डिफ़ॉल्ट मान Tहमेशा होता है default(T)। तो new Rational[1000]कभी भी संरचना निर्माताओं का आह्वान नहीं करेगा।
जेपी स्टिग नील्सन

6
इस विशिष्ट समस्या को हल करने के लिए आप denominator - 1संरचना के अंदर स्टोर कर सकते हैं , ताकि डिफ़ॉल्ट मान
0/1

3
Then if I want a container of 1000 non-default Rationals (and want to optimize away the 1000 constructions) I will use a List<Rational> rather than an array.आप किसी सरणी को किसी संरचना के लिए किसी भिन्न निर्माता को सूची में लाने की अपेक्षा क्यों करेंगे?
18'17

जवाबों:


197

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


संपादित करें: मैंने CLR में ग्रेवुल्फ़ की अंतर्दृष्टि के कारण नीचे दिए गए उत्तर को संपादित किया है।

सीएलआर मान प्रकारों को पैरामीटर रहित कंस्ट्रक्टर के लिए अनुमति देता है, लेकिन C # नहीं। मेरा मानना ​​है कि ऐसा इसलिए है क्योंकि यह एक उम्मीद का परिचय देगा कि जब यह नहीं होगा तो निर्माता को बुलाया जाएगा। उदाहरण के लिए, इस पर विचार करें:

MyStruct[] foo = new MyStruct[1000];

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

C # में मूल नियम है "किसी भी प्रकार के लिए डिफ़ॉल्ट मान किसी भी आरंभीकरण पर भरोसा नहीं कर सकता है"। अब वे पैरामीटरलेस कंस्ट्रक्टर्स को परिभाषित करने की अनुमति दे सकते थे , लेकिन तब उस कंस्ट्रक्टर को सभी मामलों में निष्पादित करने की आवश्यकता नहीं थी - लेकिन इससे अधिक भ्रम पैदा होता। (या कम से कम, इसलिए मेरा मानना ​​है कि तर्क जाता है।)

संपादित करें: अपने उदाहरण का उपयोग करने के लिए, जब कोई व्यक्ति ऐसा करना चाहेगा:

Rational[] fractions = new Rational[1000];

यह 1000 बार अपने निर्माता के माध्यम से चलना चाहिए?

  • यदि नहीं, तो हम 1000 अमान्य युक्तियों को समाप्त करते हैं
  • यदि ऐसा होता है, तो हम संभावित रूप से काम का एक भार बर्बाद कर सकते हैं यदि हम वास्तविक मूल्यों के साथ सरणी में भरने वाले हैं।

संपादित करें: (प्रश्न का थोड़ा और अधिक जवाब देना) पैरामीटर रहित कंपाइलर कंपाइलर द्वारा नहीं बनाया गया है। हालांकि यह पता चला है यह - मूल्य प्रकार कंस्ट्रक्टर्स के लिए जहाँ तक CLR का संबंध है की जरूरत नहीं है कर सकते हैं यदि आप इसे आईएल में लिखें। जब आप new Guid()C # में " " लिखते हैं जो एक सामान्य कंस्ट्रक्टर को कॉल करने पर आपको अलग-अलग आईएल का उत्सर्जन करता है। इस एसओ प्रश्न को उस पहलू पर थोड़ा और देखें ।

मुझे संदेह है कि पैरामीटरलेस निर्माणकर्ताओं के साथ ढांचे में कोई मूल्य प्रकार नहीं हैं। कोई संदेह नहीं है कि अगर मैं इसे पर्याप्त रूप से पूछूं तो एनडीपीडी मुझे बता सकती है ... तथ्य यह है कि सी # को प्रतिबंधित करता है यह मेरे लिए एक बड़ा संकेत है कि यह शायद एक बुरा विचार है।


9
कम विवरण: C ++ में, संरचना और वर्ग एक ही सिक्के के दो पहलू थे। एकमात्र वास्तविक अंतर यह है कि डिफ़ॉल्ट रूप से सार्वजनिक था और दूसरा निजी था। .Net में, एक संरचना और एक वर्ग के बीच बहुत अधिक अंतर है, और इसे समझना महत्वपूर्ण है।
जोएल कोएहॉर्न

38
@Joel: यह वास्तव में इस विशेष प्रतिबंध की व्याख्या नहीं करता है, हालांकि यह करता है?
जॉन स्कीट

6
सीएलआर मान प्रकारों को पैरामीटर रहित निर्माण करने की अनुमति देता है। और हाँ, यह इसे एक सरणी में प्रत्येक तत्व के लिए चलाएगा। C # सोचता है कि यह एक बुरा विचार है और इसे अनुमति नहीं देता है, लेकिन आप एक .NET भाषा लिख ​​सकते हैं।
जोनाथन एलन

2
क्षमा करें, मैं निम्नलिखित के साथ थोड़ा भ्रमित हूं। Rational[] fractions = new Rational[1000];यदि Rationalसंरचना के बजाय एक वर्ग है तो क्या यह काम का भार भी बर्बाद करता है ? यदि हां, तो कक्षाओं में एक डिफ़ॉल्ट ctor क्यों है?
मेरी बगल चुंबन

5
@ FifaEarthCup2014: आपको "काम के भार को कम करने" से जो मतलब है, उसके बारे में अधिक विशिष्ट होना चाहिए। लेकिन जब किसी भी तरह से, यह 1000 बार निर्माता को कॉल करने वाला नहीं है। यदि Rationalएक वर्ग है, तो आप 1000 अशक्त संदर्भों की एक सरणी के साथ समाप्त करेंगे।
जॉन स्कीट

48

एक संरचना एक मूल्य प्रकार है और एक मूल्य प्रकार घोषित होते ही डिफ़ॉल्ट मान होना चाहिए।

MyClass m;
MyStruct m2;

यदि आप दो क्षेत्रों को बिना इंस्टेंट किए हुए ऊपर घोषित करते हैं, तो डिबगर को तोड़ दें, mशून्य हो जाएगा , लेकिन m2नहीं होगा। इसे देखते हुए, एक पैरामीटर रहित निर्माण का कोई मतलब नहीं होगा, वास्तव में एक संरचना पर कोई भी निर्माणकर्ता मूल्यों को निर्दिष्ट करता है, यह बात पहले से ही घोषित करके ही मौजूद है। वास्तव में एम 2 को उपरोक्त उदाहरण में काफी खुशी के साथ इस्तेमाल किया जा सकता है और इसके तरीके कहलाते हैं, यदि कोई हो, और इसके क्षेत्र और गुणों में हेरफेर किया जाए!


3
यकीन नहीं होता कि किसी ने आपको वोट क्यों दिया। आप यहाँ पर सबसे सही उत्तर हैं।
pipTheGeek

12
C ++ में व्यवहार यह है कि यदि किसी प्रकार का डिफ़ॉल्ट कंस्ट्रक्टर है तो इसका उपयोग तब किया जाता है जब एक स्पष्ट कंस्ट्रक्टर के बिना ऐसी कोई वस्तु बनाई जाती है। इसका उपयोग C # में डिफ़ॉल्ट निर्माता के साथ m2 को इनिशियलाइज़ करने के लिए किया जा सकता है, यही कारण है कि यह उत्तर सहायक नहीं है।
मत्ती M

3
onester: यदि आप घोषणा करते समय अपने स्वयं के निर्माता को कॉल करना नहीं चाहते हैं, तो ऐसे डिफ़ॉल्ट निर्माता को परिभाषित न करें! :) यही Motti कह रही है
स्टीफन मोनोव

8
@Tarik। मैं इससे सहमत नहीं हूँ। इसके विपरीत, एक पैरामीटर रहित निर्माता पूर्ण अर्थ लगाएगा: यदि मैं "मैट्रिक्स" संरचना बनाना चाहता हूं, तो हमेशा डिफ़ॉल्ट मान के रूप में एक पहचान मैट्रिक्स होता है, आप इसे अन्य तरीकों से कैसे कर सकते हैं?
एलो

1
मैं कर रहा हूँ यकीन है कि मैं पूरी तरह से सहमत नहीं के साथ "वास्तव में एम 2 काफी खुशी से इस्तेमाल किया जा सकता .." । यह पिछले सी # में सही हो सकता है, लेकिन यह एक संरचना को घोषित करने के लिए एक संकलक त्रुटि है, newयह नहीं , फिर अपने सदस्यों का उपयोग करने का प्रयास करें
कायुस जार्ड

18

यद्यपि CLR इसे अनुमति देता है, C # एक डिफ़ॉल्ट पैरामीटर-कम कंस्ट्रक्टर के लिए संरचना की अनुमति नहीं देता है। इसका कारण यह है कि, मान प्रकार के लिए, डिफ़ॉल्ट रूप से कंपाइलर न तो डिफ़ॉल्ट कंस्ट्रक्टर उत्पन्न करते हैं, न ही वे डिफॉल्ट कंस्ट्रक्टर को कॉल उत्पन्न करते हैं। इसलिए, भले ही आप एक डिफ़ॉल्ट कंस्ट्रक्टर को परिभाषित करने के लिए हुआ हो, इसे कॉल नहीं किया जाएगा, और यह केवल आपको भ्रमित करेगा।

ऐसी समस्याओं से बचने के लिए, उपयोगकर्ता द्वारा C # संकलक एक डिफ़ॉल्ट कंस्ट्रक्टर की परिभाषा को अस्वीकार कर देता है। और क्योंकि यह एक डिफॉल्ट कंस्ट्रक्टर उत्पन्न नहीं करता है, आप उन्हें परिभाषित करते समय फ़ील्ड को इनिशियलाइज़ नहीं कर सकते हैं।

या बड़ा कारण यह है कि एक संरचना एक मूल्य प्रकार है और मूल्य प्रकारों को एक डिफ़ॉल्ट मान द्वारा प्रारंभ किया जाता है और निर्माणकर्ता को आरंभीकरण के लिए उपयोग किया जाता है।

आपको newकीवर्ड के साथ अपनी संरचना को त्वरित करने की आवश्यकता नहीं है । इसके बजाय यह एक इंट की तरह काम करता है; आप सीधे इसे एक्सेस कर सकते हैं।

संरचना में स्पष्ट पैरामीटर रहित कंस्ट्रक्टर नहीं हो सकते। संरचना सदस्यों को स्वचालित रूप से उनके डिफ़ॉल्ट मानों के लिए आरंभिक किया जाता है।

संरचना के लिए एक डिफ़ॉल्ट (पैरामीटर-कम) निर्माता सभी शून्य स्थिति की तुलना में अलग-अलग मान सेट कर सकता है जो अप्रत्याशित व्यवहार होगा। .NET रनटाइम इसलिए किसी संरचना के लिए डिफ़ॉल्ट निर्माणकर्ताओं को प्रतिबंधित करता है।


यह उत्तर अब तक का सबसे अच्छा है। अंत में प्रतिबंधित करने के पूरे बिंदु आश्चर्य से बचने के लिए है MyStruct s;जो आपके द्वारा प्रदान किए गए डिफ़ॉल्ट निर्माणकर्ता को नहीं बुला रहा है।
20

1
विवरण के लिए आपका धन्यवाद। तो यह केवल एक संकलक की कमी है जिसे सुधारना होगा, पैरामीटर रहित निर्माणकर्ताओं को मना करने का कोई सैद्धांतिक अच्छा कारण नहीं है (जैसे ही वे केवल एक्सेस गुणों तक सीमित हो सकते हैं)।
एलो

16

आप एक स्थिर संपत्ति बना सकते हैं जो एक डिफ़ॉल्ट "तर्कसंगत" संख्या को शुरू और वापस करती है:

public static Rational One => new Rational(0, 1); 

और इसका उपयोग करें:

var rat = Rational.One;

24
इस मामले में, Rational.Zeroथोड़ा कम भ्रमित हो सकता है।
केविन

13

कम विवरण:

C ++ में, संरचना और वर्ग एक ही सिक्के के दो पहलू थे। एकमात्र वास्तविक अंतर यह है कि एक डिफ़ॉल्ट रूप से सार्वजनिक था और दूसरा निजी था।

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


7
आपको इस बारे में थोड़ा और स्पष्ट होना होगा कि यह मूल्य बनाम संदर्भ प्रकार विभाजन से कैसे
जुड़ा है

मान प्रकार में एक डिफ़ॉल्ट मान होता है- वे अशक्त नहीं होते हैं, भले ही आप एक निर्माता को परिभाषित न करें। जबकि पहली नज़र में यह एक डिफ़ॉल्ट कंस्ट्रक्टर को परिभाषित करने से भी पीछे नहीं हटता है, इस संरचना का उपयोग करके ढांचों के बारे में कुछ धारणाएं बनाने के लिए आंतरिक का उपयोग करता है।
जोएल कोएहॉर्न 21

@annakata: अन्य निर्माणकर्ता शायद कुछ परिदृश्यों में उपयोगी हैं जिनमें परावर्तन शामिल है। इसके अलावा, यदि जेनरिक को कभी भी एक "नए" अवरोध के लिए अनुमति देने के लिए बढ़ाया गया था, तो यह उन संरचनाओं के लिए उपयोगी होगा जो उनका अनुपालन कर सकते हैं।
सुपरकैट

@annakata मेरा मानना ​​है कि यह इसलिए है क्योंकि C # की एक विशेष मजबूत आवश्यकता है जिसे newवास्तव में एक निर्माता को कॉल करने के लिए लिखा जाना चाहिए। सी ++ में कंस्ट्रक्टर्स को ऐरे के ऐलान या इंस्टेंटेशन पर छिपे हुए तरीकों से बुलाया जाता है। C # में या तो सब कुछ एक पॉइंटर है, इसलिए null पर शुरू करें, या तो यह एक स्ट्रक्चर है और इसे किसी चीज़ पर शुरू करना चाहिए, लेकिन जब आप नहीं लिख सकते हैं new... (सरणी init की तरह), तो यह एक मजबूत C # नियम को तोड़ देगा।
v.oddou

3

मैं देर से समाधान के बराबर नहीं दिख रहा हूँ जो मैं देने जा रहा हूँ, इसलिए यहाँ यह है।

किसी भी मान में डिफ़ॉल्ट 0 से मान स्थानांतरित करने के लिए ऑफ़सेट का उपयोग करें। यहां सीधे खेतों तक पहुंचने के बजाय गुणों का उपयोग किया जाना चाहिए। (हो सकता है कि संभव सी # 7 सुविधा के साथ आप बेहतर संपत्ति वाले खेतों को परिभाषित करें ताकि वे कोड में सीधे एक्सेस होने से सुरक्षित रहें।)

यह समाधान केवल मूल्य प्रकार (कोई रेफरी प्रकार या अशक्त संरचना) के साथ सरल संरचनाओं के लिए काम करता है।

public struct Tempo
{
    const double DefaultBpm = 120;
    private double _bpm; // this field must not be modified other than with its property.

    public double BeatsPerMinute
    {
        get => _bpm + DefaultBpm;
        set => _bpm = value - DefaultBpm;
    }
}

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

क्षेत्र के रूप में enums के साथ उदाहरण।

public struct Difficaulty
{
    Easy,
    Medium,
    Hard
}

public struct Level
{
    const Difficaulty DefaultLevel = Difficaulty.Medium;
    private Difficaulty _level; // this field must not be modified other than with its property.

    public Difficaulty Difficaulty
    {
        get => _level + DefaultLevel;
        set => _level = value - DefaultLevel;
    }
}

जैसा कि मैंने कहा कि यह चाल सभी मामलों में काम नहीं कर सकती है, भले ही संरचना में केवल मूल्य क्षेत्र हों, केवल आप जानते हैं कि यह आपके मामले में काम करता है या नहीं। बस जाँच करें। लेकिन आप सामान्य विचार प्राप्त करते हैं।


यह मेरे द्वारा दिए गए उदाहरण के लिए एक अच्छा समाधान है, लेकिन यह वास्तव में केवल एक उदाहरण माना जाता था, सवाल सामान्य है।
मोति

2

बस विशेष-मामला है। यदि आप 0 के एक अंश और 0 के एक भाजक को देखते हैं, तो यह दिखावा करें कि इसमें वे मूल्य हैं जो आप वास्तव में चाहते हैं।


5
मुझे व्यक्तिगत रूप से इस तरह का व्यवहार करने के लिए मेरी कक्षाएं / संरचना पसंद नहीं है। चुपचाप असफल होना (या जिस तरह से देव अनुमान आपके लिए सबसे अच्छा है) उबरने वाली गलतियों की राह है।
बोरिस ने

2
+1 यह एक अच्छा जवाब है, क्योंकि मूल्य प्रकारों के लिए, आपको उनके डिफ़ॉल्ट मूल्य को ध्यान में रखना होगा। आइए आपको इसके व्यवहार के साथ डिफ़ॉल्ट मान "सेट" करते हैं।
इलिडान्स 4 चाहता है कि मोनिका वापस जूल

यह ठीक उसी प्रकार है जैसे वे Nullable<T>(जैसे int?) कक्षाएं लागू करते हैं ।
जोनाथन एलन

यह बहुत बुरा विचार है। 0/0 हमेशा एक अमान्य अंश (NaN) होना चाहिए। यदि कोई व्यक्ति new Rational(x,y)जहां x और y 0 होता है, तो क्या होगा ?
माइक रोसॉफ्ट

यदि आपके पास एक वास्तविक निर्माता है तो आप एक अपवाद को फेंक सकते हैं, एक वास्तविक 0/0 को होने से रोक सकते हैं। या यदि आप ऐसा करना चाहते हैं, तो आपको डिफ़ॉल्ट और 0/0 के बीच अंतर करने के लिए एक अतिरिक्त बूल जोड़ना होगा।
जोनाथन एलन

2

मैं क्या उपयोग करता है अशक्त coalescing ऑपरेटर (??) इस तरह एक समर्थन क्षेत्र के साथ संयुक्त है:

public struct SomeStruct {
  private SomeRefType m_MyRefVariableBackingField;

  public SomeRefType MyRefVariable {
    get { return m_MyRefVariableBackingField ?? (m_MyRefVariableBackingField = new SomeRefType()); }
  }
}

उम्मीद है की यह मदद करेगा ;)

नोट: अशक्त coalescing असाइनमेंट वर्तमान में C # 8.0 के लिए एक फीचर प्रस्ताव है।


1

आप डिफ़ॉल्ट निर्माता को परिभाषित नहीं कर सकते क्योंकि आप C # का उपयोग कर रहे हैं।

.NET में संरचनाओं में डिफ़ॉल्ट कंस्ट्रक्टर हो सकते हैं, हालांकि मुझे इसका समर्थन करने वाली किसी भी विशिष्ट भाषा का पता नहीं है।


C # में, वर्ग और संरचनाएं शब्दार्थ रूप से भिन्न हैं। एक संरचना एक मूल्य प्रकार है, जबकि एक वर्ग एक संदर्भ प्रकार है।
टॉम सरदयू

-1

यहाँ कोई डिफ़ॉल्ट कंस्ट्रक्टर दुविधा का मेरा समाधान है। मुझे पता है कि यह एक देर से समाधान है, लेकिन मुझे लगता है कि यह ध्यान देने योग्य है कि यह एक समाधान है।

public struct Point2D {
    public static Point2D NULL = new Point2D(-1,-1);
    private int[] Data;

    public int X {
        get {
            return this.Data[ 0 ];
        }
        set {
            try {
                this.Data[ 0 ] = value;
            } catch( Exception ) {
                this.Data = new int[ 2 ];
            } finally {
                this.Data[ 0 ] = value;
            }
        }
    }

    public int Z {
        get {
            return this.Data[ 1 ];
        }
        set {
            try {
                this.Data[ 1 ] = value;
            } catch( Exception ) {
                this.Data = new int[ 2 ];
            } finally {
                this.Data[ 1 ] = value;
            }
        }
    }

    public Point2D( int x , int z ) {
        this.Data = new int[ 2 ] { x , z };
    }

    public static Point2D operator +( Point2D A , Point2D B ) {
        return new Point2D( A.X + B.X , A.Z + B.Z );
    }

    public static Point2D operator -( Point2D A , Point2D B ) {
        return new Point2D( A.X - B.X , A.Z - B.Z );
    }

    public static Point2D operator *( Point2D A , int B ) {
        return new Point2D( B * A.X , B * A.Z );
    }

    public static Point2D operator *( int A , Point2D B ) {
        return new Point2D( A * B.Z , A * B.Z );
    }

    public override string ToString() {
        return string.Format( "({0},{1})" , this.X , this.Z );
    }
}

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

public struct Rational {
    private long[] Data;

    public long Numerator {
        get {
            try {
                return this.Data[ 0 ];
            } catch( Exception ) {
                this.Data = new long[ 2 ] { 0 , 1 };
                return this.Data[ 0 ];
            }
        }
        set {
            try {
                this.Data[ 0 ] = value;
            } catch( Exception ) {
                this.Data = new long[ 2 ] { 0 , 1 };
                this.Data[ 0 ] = value;
            }
        }
    }

    public long Denominator {
        get {
            try {
                return this.Data[ 1 ];
            } catch( Exception ) {
                this.Data = new long[ 2 ] { 0 , 1 };
                return this.Data[ 1 ];
            }
        }
        set {
            try {
                this.Data[ 1 ] = value;
            } catch( Exception ) {
                this.Data = new long[ 2 ] { 0 , 1 };
                this.Data[ 1 ] = value;
            }
        }
    }

    public Rational( long num , long denom ) {
        this.Data = new long[ 2 ] { num , denom };
        /* Todo: Find GCD etc. */
    }

    public Rational( long num ) {
        this.Data = new long[ 2 ] { num , 1 };
        this.Numerator = num;
        this.Denominator = 1;
    }
}

2
यह बहुत बुरा कोड है। किसी संरचना में आपके पास सरणी संदर्भ क्यों है? खेतों के रूप में आपके पास केवल X और Y समन्वय क्यों नहीं है? और प्रवाह नियंत्रण के लिए अपवादों का उपयोग करना एक बुरा विचार है; आपको आमतौर पर अपना कोड इस तरह से लिखना चाहिए कि NullReferenceException कभी न हो। यदि आपको वास्तव में इसकी आवश्यकता है - हालांकि ऐसा निर्माण एक संरचना के बजाय एक वर्ग के लिए बेहतर अनुकूल होगा - तो आपको आलसी आरंभीकरण का उपयोग करना चाहिए। (और तकनीकी रूप से, आप हैं - पूरी तरह से हर एक में पूरी तरह से अनावश्यक हैं, लेकिन एक समन्वय की पहली सेटिंग - प्रत्येक समन्वय को दो बार सेट करते हैं।)
माइक रोसॉफ्ट

-1
public struct Rational 
{
    private long numerator;
    private long denominator;

    public Rational(long num = 0, long denom = 1)   // This is allowed!!!
    {
        numerator   = num;
        denominator = denom;
    }
}

5
इसकी अनुमति है लेकिन इसका उपयोग तब नहीं किया जाता है जब कोई पैरामीटर निर्दिष्ट नहीं किए जाते हैं ideone.com/xsLloQ
Motti
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.