गेट्स, सेटर और गुण सर्वोत्तम प्रथाओं। जावा बनाम सी #


92

मैं अभी C # क्लास ले रहा हूं और चीजों को करने का सबसे अच्छा तरीका जानने की कोशिश कर रहा हूं। मैं एक जावा बैकग्राउंड से आता हूं और इसलिए मैं केवल जावा बेस्ट-प्रैक्टिस से परिचित हूं; मैं एक C # नौसिखिया हूँ!

जावा में यदि मेरे पास कोई निजी संपत्ति है, तो मैं यह करता हूं;

private String name;

public void setName(String name) {
   this.name = name;
}

public String getName() {
   return this.name;
}

C # में, मैं देखता हूं कि ऐसा करने के कई तरीके हैं।

मैं इसे जावा की तरह कर सकता हूं:

private string name;

public void setName(string name) {
   this.name = name;
}

public string getName() {
   return this.name;
}

या मैं इसे इस तरह से कर सकता हूं:

private string name;

public string Name {
   get { return name; }
   set { name = value; }
}

या:

public string Name { get; set; }

मुझे कौन सा उपयोग करना चाहिए, और प्रत्येक दृष्टिकोण के साथ शामिल किए गए कैविएट या सूक्ष्मताएं क्या हैं? कक्षाएं बनाते समय, मैं सामान्य सर्वोत्तम प्रथाओं का पालन कर रहा हूं जो मुझे जावा (विशेष रूप से प्रभावी जावा पढ़ने) से पता है। इसलिए, उदाहरण के लिए, मैं अपरिवर्तनीयता का पक्ष ले रहा हूं (केवल आवश्यक होने पर ही निपटान प्रदान करता है)। मैं यह देखने के लिए उत्सुक हूं कि ये अभ्यास C # में बसने और पाने के विभिन्न तरीकों के साथ कैसे फिट होते हैं; अनिवार्य रूप से, मैं जावा दुनिया से C # में सर्वोत्तम प्रथाओं का अनुवाद कैसे करूंगा?

संपादित करें

मैं इसे जॉन स्कीट के उत्तर के लिए एक टिप्पणी के रूप में पोस्ट कर रहा था, लेकिन तब यह लंबा हो गया:

एक गैर-तुच्छ संपत्ति (यानी, महत्वपूर्ण प्रसंस्करण और सत्यापन के साथ शायद) के बारे में क्या? क्या मैं अभी भी इसे एक सार्वजनिक संपत्ति के माध्यम से उजागर कर सकता हूं लेकिन तर्क में getऔर इसमें संलग्न तर्क के साथ set? मुझे समर्पित सेटर और गेट्टर मेथड (संबद्ध प्रसंस्करण और सत्यापन तर्क के साथ) क्यों करना चाहिए।

जवाबों:


88

प्री-सी # 6

मैं एक तुच्छ संपत्ति के लिए इनमें से अंतिम का उपयोग करूंगा। ध्यान दें कि मैं इसे एक सार्वजनिक संपत्ति कहूंगा क्योंकि गेटर्स और सेटर दोनों सार्वजनिक हैं।

अपरिवर्तनीयता स्वचालित रूप से कार्यान्वित गुणों के साथ दर्द का एक सा है - आप एक ऑटो-प्रॉपर्टी नहीं लिख सकते हैं जिसमें केवल एक गेटर है; आप आ सकते हैं निकटतम:

public string Foo { get; private set; }

जो वास्तव में अपरिवर्तनीय नहीं है ... आपकी कक्षा के बाहर अपरिवर्तनीय है। इसलिए आप इसके बजाय एक वास्तविक रीड-ओनली प्रॉपर्टी का उपयोग करना चाहते हैं:

private readonly string foo;
public string Foo { get { return foo; } }

आप निश्चित रूप से लिखना नहीं चाहते हैं getName()और setName()। में कुछ मामलों में यह लिखने प्राप्त / सेट के बजाय गुणों का उपयोग करके तरीकों को समझ में आता है, खासकर यदि वे महंगा हो सकता है और आप उस पर जोर देना चाहते हैं। हालाँकि, आप तरीकों के लिए PascalCase के .NET नामकरण सम्मेलन का पालन करना चाहते हैं, और आप इस तरह से एक तुच्छ संपत्ति नहीं चाहते हैं, वैसे भी सामान्य तरीकों से लागू किया जा सकता है - एक संपत्ति यहां बहुत अधिक मुहावरेदार है।

सी # 6

हुर्रे, हमारे पास अंततः उचित रीड-ओनली स्वचालित रूप से लागू गुण हैं:

// This can only be assigned to within the constructor
public string Foo { get; }

इसी तरह केवल पढ़ने के लिए गुण है जिसके लिए कर की जरूरत कुछ काम करने के लिए, आप सदस्य शरीर गुणों का उपयोग कर सकते हैं:

public double Area => height * width;

5
अधिक सटीक: कोई भी कोड reiew इंगित करेगा java रास्ता एक हैक है जो वैध लैंग्वेज और (!) रनटाइम निर्माण को दरकिनार करता है और संपत्ति के उपयोग को विपत्ति (यानी object.property = "value") के रूप में मार देता है। कुछ टीमों में यह रवैया के बारे में एक अच्छी बात का परिणाम होगा - एक प्रतियोगी पर उपयोग करने के लिए उस दृष्टिकोण को डालने के लिए एक प्रोत्साहन के साथ संयुक्त वरिष्ठता पर निर्भर करता है। गंभीरता से, न तो लड़ाई लड़ता है। विशेष रूप से जावा "रास्ता" एक हैक है जिसे वास्तविक संपत्ति समर्थन के लिए लैंग गेज को संशोधित नहीं करने के लिए चुना गया था।
टॉम 24

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

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

2
@ आर्टिंद्रू: हां, मैं इससे अवगत हूं। केवल-पढ़ने के लिए संपत्ति लिखना पूरी तरह से संभव है। लेकिन आप एक सेट एक्सेसर के बिना स्वचालित रूप से कार्यान्वित की गई संपत्ति की घोषणा नहीं कर सकते ।
जॉन स्कीट


17

अगर आपको कुछ डेटा स्टोर करने के लिए एक चर चाहिए:

public string Name { get; set; }

इसे केवल पढ़ने के लिए प्रकट करना चाहते हैं?

public string Name { get; private set; }

या इससे भी बेहतर ...

private readonly string _name;

...

public string Name { get { return _name; } }

संपत्ति निर्दिष्ट करने से पहले कुछ मूल्य जाँच करना चाहते हैं?

public string Name 
{
   get { return m_name; }
   set
   {
      if (value == null)
         throw new ArgumentNullException("value");

      m_name = value;
   }
}

सामान्य तौर पर, GetXyz () और SetXyz () केवल कुछ मामलों में उपयोग किए जाते हैं, और आपको सही महसूस होने पर बस अपने आंत का उपयोग करना होगा। सामान्य तौर पर, मैं कहूंगा कि मुझे सबसे अधिक / सेट गुणों की उम्मीद है जिसमें बहुत सारे तर्क नहीं हैं और बहुत कम हैं, यदि कोई हो, तो अप्रत्याशित दुष्प्रभाव। यदि किसी संपत्ति के मूल्य को पढ़ने के लिए किसी सेवा को प्राप्त करने या उपयोगकर्ता से इनपुट प्राप्त करने की आवश्यकता होती है, ताकि मैं उस वस्तु का निर्माण कर सकूं, तो मैं इसे एक विधि में लपेट दूंगा, और इसके BuildXyz()बजाय कुछ ऐसा कहूंगा GetXyz()


2
मैं गुणों में अपवाद नहीं फेंकूंगा, मैं ऐसे विशिष्ट व्यवहार को निर्दिष्ट करने के लिए अनुबंध के साथ विधि का उपयोग करता हूं। अगर कोई प्रॉपर्टी टाइप इंट की है, तो मैं चाहता हूं कि हर इंट क्वालिफाई हो। जो कुछ अपवाद के लिए कॉल करता है वह मेरे विचार में सरल नहीं है , मेरे अनुसार INotifyPropertyChanged प्रकार के इनवॉइस उस पंक्ति में अधिक हैं।
फ्लिंडबर्ग

3
निजी सेटर! = अपरिवर्तनीय
piedar

पिडार सही है। एक निजी सेटर का मतलब है कि मैं असाइनमेंट नहीं कर सकता, लेकिन मैं अभी भी उपयोग कर सकता हूं myList.Add(), उदाहरण के लिए (जब तक ऑब्जेक्ट बदलने के लिए सामने आता है, यह परिवर्तनशील है)।

1
@flindeberg क्षमा करें, लेकिन मैं असहमत हूं ... यदि आपके पास Min/ Maxमान के साथ प्रगति बार मिला है तो क्या होगा । आप यह सुनिश्चित करना चाहते हैं Max > Min? एक के बाद SetRange(Min, Max)हो सकता है मेकअप भावना लेकिन फिर कैसे आप उन मूल्यों को वापस पढ़ने के लिए जा रहे हैं? Readonly न्यूनतम / अधिकतम गुण? अवैध इनपुट के लिए अपवाद को फेंकना इसे संभालने का सबसे साफ तरीका है।
बेसिक

12

C # में गुणों का उपयोग करें, न कि / निर्धारित तरीके। वे आपकी सुविधा के लिए वहाँ हैं और यह मुहावरा है।

अपने दो C # उदाहरणों के लिए, एक बस दूसरे के लिए सिंथेटिक चीनी है। ऑटो प्रॉपर्टी का उपयोग करें यदि आपको ज़रूरत है तो उदाहरण चर के चारों ओर एक सरल आवरण है, जब आपको गेटर और / या सेटर में तर्क जोड़ने की आवश्यकता होती है तो पूर्ण संस्करण का उपयोग करें।


5

C # के पक्ष में, और / या सेट के लिए निजी क्षेत्रों को उजागर करने के लिए गुण। आपके द्वारा उल्लिखित थाइ फॉर्म एक ऑटोप्रोपर्टी है जहां आपके लिए छिपे हुए धुरी समर्थन क्षेत्र को स्वचालित रूप से प्राप्त और सेट किया जाता है।

मैं जब संभव हो तो ऑटो गुणों का पक्ष लेता हूं लेकिन आपको कभी भी C # में सेट / पेयर पेयर नहीं करना चाहिए।


5
public string Name { get; set; }

यह बस एक ऑटो-कार्यान्वित संपत्ति है , और तकनीकी रूप से एक सामान्य संपत्ति के समान है। संकलन करते समय एक बैकिंग फ़ील्ड बनाया जाएगा।

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

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


4

भले ही आप C # में से किस तरह का चयन करते हैं अंतिम परिणाम समान है। आपको अलग-अलग गेटटर और सेटर विधियों के साथ एक बैकिनिंग चर मिलेगा। गुणों का उपयोग करके आप सर्वोत्तम प्रथाओं का पालन कर रहे हैं और इसलिए यह बात है कि आप कितना वर्बोज़ प्राप्त करना चाहते हैं।

व्यक्तिगत रूप से मैं ऑटो-गुण, अंतिम संस्करण चुनूंगा: public string Name { get; set; }क्योंकि वे कम से कम जगह लेते हैं। और आप हमेशा भविष्य में इनका विस्तार कर सकते हैं यदि आपको सत्यापन जैसी किसी चीज़ की आवश्यकता है।


4

जब भी संभव हो मैं सार्वजनिक string Name { get; set; }रूप से पसंद करता हूं क्योंकि यह बहुत आसान है और आसानी से पठनीय है। हालांकि, ऐसे समय हो सकते हैं जब यह आवश्यक हो

private string name;

public string Name {
   get { return name; }
   set { name = value; }
}

2
क्या आप बता सकते हैं कि कब और क्यों इस तरह की चीज जरूरी है?
जेसपर

अभी मैं 2 संस्करण का उपयोग करने के लिए एक कारण के बारे में नहीं सोच सकता। मैंने केवल यह कहा कि 'ऐसा समय हो सकता है जब यह आवश्यक हो।' जब तक मैं सकारात्मक नहीं हूँ, मुझे निरपेक्षता का उपयोग करने से नफरत है।
SquidScareMe

3
और यह 'लोलज' क्यों है? आप टिप्पणी के लिए अपना समर्थन बढ़ाकर दिखा सकते हैं।
SquidScareMe

1
स्पष्ट बैकिंग फ़ील्ड का उपयोग करने का एक कारण यह है कि जब आप मूल्य के विरुद्ध परमाणु / थ्रेड-सुरक्षित संचालन करना चाहते हैं
बुनियादी

4

C # में पसंदीदा तरीका गुणों के बजाय getX()और setX()विधियों के माध्यम से है । इसके अलावा, ध्यान दें कि C # की आवश्यकता नहीं है कि गुणों में एक प्राप्त और एक सेट दोनों हैं - आपके पास केवल-गुण और सेट-केवल गुण हो सकते हैं।

public boolean MyProperty
{
    get { return something; }
}

public boolean MyProperty
{
    set { this.something = value; }
}

4

पहले मुझे समझाने की कोशिश करें कि आपने क्या लिखा है:

// private member -- not a property
private string name;

/// public method -- not a property
public void setName(string name) {
   this.name = name;
}

/// public method -- not a property
public string getName() {
   return this.name;
}

// yes it is property structure before .Net 3.0
private string name;
public string Name {
   get { return name; }
   set { name = value; }
}

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

.Net फ्रेमवर्क 3.0 के साथ

// this style is introduced, which is more common, and suppose to be best
public string Name { get; set; }

//You can more customize it
public string Name
{
    get;
    private set;    // means value could be set internally, and accessed through out
}

आपको सी # में बेहतर भाग्य की कामना


3

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


2

यहां अधिकांश उत्तरों की तरह, स्वचालित गुणों का उपयोग करें। सहज, कोड की कम लाइनें और यह अधिक साफ है। यदि आपको अपनी कक्षा क्रमबद्ध करनी चाहिए, तो कक्षा [Serializable]को [DataConract]विशेषता के साथ चिह्नित करें । और यदि आप [DataContract]सदस्य को चिन्हित कर रहे हैं

[DataMember(Name="aMoreFriendlyName")]
public string Name { get; set; }

निजी या सार्वजनिक सेटर आपकी प्राथमिकता पर निर्भर करता है।

यह भी ध्यान दें कि स्वचालित गुणों को गेटर्स और सेटर (सार्वजनिक या निजी) दोनों की आवश्यकता होती है।

/*this is invalid*/
public string Name 
{ 
    get; 
   /* setter omitted to prove the point*/
}

वैकल्पिक रूप से, यदि आप केवल प्राप्त / सेट करना चाहते हैं, तो एक बैकिंग फ़ील्ड स्वयं बनाएं


0

मुझे कौन सा उपयोग करना चाहिए, और प्रत्येक दृष्टिकोण के साथ शामिल किए गए कैविएट या सूक्ष्मताएं क्या हैं?

जब गुणों के साथ जा रहे हैं तो एक कैविट है जिसका अभी तक उल्लेख नहीं किया गया है: गुणों के साथ आपके पास अपने गेटर्स या बसने वालों का कोई पैरामीरिजेशन नहीं हो सकता है।

उदाहरण के लिए कल्पना कीजिए कि आप एक सूची आइटम प्राप्त करना चाहते हैं और उसी समय एक फ़िल्टर भी लागू करना चाहते हैं। एक विधि पाने के साथ आप कुछ लिख सकते हैं:

obj.getItems(filter);

इसके विपरीत, एक संपत्ति के साथ आपको पहले सभी आइटम वापस करने के लिए मजबूर किया जाता है

obj.items

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

obj.itemsFilteredByX
obj.itemsFilteredByY

कभी-कभी एक उपद्रव हो सकता है जब आप एक संपत्ति के साथ शुरू करते हैं, उदाहरण के लिए obj.itemsऔर फिर बाद में पता चला कि गेट्टर- या सेटर-पैराड्राइज़ेशन की आवश्यकता है या क्लास-एपीआई उपयोगकर्ता के लिए चीजों को आसान बना देगा। अब आपको अपने एपीआई को फिर से लिखना होगा और अपने कोड में उन सभी स्थानों को संशोधित करना होगा जो इस संपत्ति का उपयोग करते हैं या एक वैकल्पिक समाधान ढूंढते हैं। इसके विपरीत, एक गेट-मेथड के साथ, उदाहरण के लिए obj.getItems(), आप एक वैकल्पिक "कॉन्फ़िगरेशन" ऑब्जेक्ट को स्वीकार करने के लिए बस अपने तरीके के हस्ताक्षर का विस्तार कर सकते हैं , जैसे obj.getItems(options)कि उन सभी जगहों को फिर से लिखना, जो आपके तरीके को कहते हैं।

कहा जा रहा है, सी # में (ऑटो-कार्यान्वित) गुण अभी भी बहुत उपयोगी शॉर्टकट हैं (यहां बताए गए विभिन्न कारणों के लिए) क्योंकि अधिकांश समय पैरामीट्रिज़ेशन की आवश्यकता नहीं हो सकती है - लेकिन यह कैविटी खड़ा है।

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