निजी चर बनाम संपत्ति?


41

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

private string myValue;
public string MyValue
{
   get { return myValue; }
   set { myValue = value; }
}

क्या एक सम्मेलन है जो यह निर्धारित करता है कि हमें अपनी कक्षाओं के अंदर चर के मूल्यों को कैसे असाइन करना चाहिए? उदाहरण के लिए यदि मेरे पास उसी वर्ग के अंदर एक विधि है, तो मुझे इसे संपत्ति का उपयोग करके या निजी चर का उपयोग करके असाइन करना चाहिए। मैंने इसे दोनों तरीकों से किया है, इसलिए मैं सोच रहा था कि क्या यह पसंद है या प्रदर्शन एक कारक है (मामूली, शायद)।

जवाबों:


23

मैं इसे एक कदम आगे ले जाऊंगा, और इसे 3 मामलों में लाऊंगा। यद्यपि प्रत्येक पर भिन्नताएं हैं, यह वह नियम है जो मैं उस समय के अधिकांश उपयोग करता हूं जब सी # प्रोग्रामिंग।

2 और 3 के मामले में, हमेशा प्रॉपर्टी एक्सेसर (फील्ड वेरिएबल नहीं) पर जाएं। और मामले 1 में, आप इस विकल्प को बनाने से भी बच जाते हैं।

1.) अचल संपत्ति (कंस्ट्रक्टर में उत्तीर्ण, या निर्माण के समय बनाई गई)। इस मामले में, मैं केवल पढ़ने के लिए संपत्ति के साथ एक क्षेत्र चर का उपयोग करता हूं। मैं इसे एक निजी सेटर पर चुनता हूं, क्योंकि एक निजी सेटर अपरिवर्तनीयता की गारंटी नहीं देता है।

public class Abc
{ 
  private readonly int foo;

  public Abc(int fooToUse){
    foo = fooToUse;
  }

  public int Foo { get{ return foo; } }
}

2.) POCO चर। एक साधारण चर जो किसी भी सार्वजनिक / निजी दायरे में प्राप्त / सेट किया जा सकता है। इस मामले में मैं सिर्फ एक स्वचालित संपत्ति का उपयोग करूंगा।

public class Abc
{ 
  public int Foo {get; set;}
}

3.) ViewModel बाध्यकारी गुण। INotifyPropertyChanged का समर्थन करने वाली कक्षाओं के लिए, मुझे लगता है कि आपको एक निजी, बैकिंग फ़ील्ड चर की आवश्यकता है।

public class Abc : INotifyPropertyChanged
{
  private int foo;

  public int Foo
  {
    get { return foo; }
    set { foo = value;  OnPropertyChanged("foo"); }
  }
}

2
MVVM उदाहरण के लिए +1। वास्तव में यह सवाल पहले स्थान पर था।
एडवर्ड

4
+1: AOP के साथ 2/3 मिलाएं और आपके पास INPC का उपयोग करने का एक शानदार तरीका है। [सूचित करता है] सार्वजनिक int फू {get; सेट; }
स्टीवन एवर्स

1
@Job किसी भी वर्ग तक पहुँचने के लिए, एक निजी सेटर अपरिवर्तनीयता के लिए पर्याप्त है। हालांकि, कक्षा के अंदर, निजी सेटर प्रारंभिक निर्माण के बाद, मूल्य की बार-बार सेटिंग्स को रोकता नहीं है। 'प्राइवेट रीडायनली सेट' जैसी भाषा की सुविधा इस समस्या के आसपास वैचारिक रूप से काम कर सकती है, लेकिन यह मौजूद नहीं है।
शेल्डन वार्केंटिन

1
मैं C # में नया हूं, इसलिए मुझे बताएं, इसके बजाय उपयोग क्यों करें ? public int Foo {get; set;}public int Foo

1
यदि एक वर्ग या संरचना एक POCO या PODS के रूप में व्यवहार करने जा रही है, तो गुणों में फ़ील्ड लपेटने का क्या वास्तविक लाभ है? मैं पूरी तरह से समझता हूं कि किसी वर्ग या संरचना की आवश्यकता होने पर, या अपनी सामग्री के संबंध में आक्रमणकारियों को बनाए रखने के लिए (शायद अन्य वस्तुओं को सुनिश्चित करने के लिए उन्हें अपडेट करने के लिए अद्यतन किया जाता है), लेकिन जब कोई वर्ग या संरचना होती है, तो संपत्तियों में रैपिंग फ़ील्ड उपयोगी होती है। निर्दिष्ट करता है कि उपभोक्ता किसी भी क्रम में प्रतिबंध या साइड-इफेक्ट्स के बिना किसी भी मूल्य को लिख सकते हैं, संभवत: एक सदस्य एक्सेसर में कौन से उपयोगी व्यवहार जोड़े जा सकते हैं?
सुपरकैट

18

आमतौर पर, मैं कहूंगा कि कंस्ट्रक्टर में फ़ील्ड को असाइन करें और हर जगह संपत्ति का उपयोग करें। इस तरह, अगर कोई संपत्ति में कार्यक्षमता जोड़ता है, तो आप इसे कहीं भी याद नहीं करेंगे।

यह निश्चित रूप से एक प्रदर्शन कारक नहीं है। ऑप्टिमाइज़र आपके लिए एक सरल मिल या सेट इनलाइन करेगा और अंतिम MSIL कोड संभवतः समान होगा।


कंस्ट्रक्टर में फ़ील्ड का उपयोग करने का कोई विशेष कारण? अजीब दुष्प्रभाव का कम मौका?
हस्ताक्षर करें

4
@ संकेत: मेरा अनुमान है कि यदि संपत्ति पर सत्यापन (अभी या भविष्य में) है, तो आप निर्माण के दौरान सत्यापन विफल होने का जोखिम नहीं उठाना चाहते हैं। इस स्तर पर वैधता तर्कसंगत नहीं है, क्योंकि ऑब्जेक्ट को तब तक स्थिर रहने की गारंटी नहीं दी जा सकती जब तक कि कंस्ट्रक्टर खत्म नहीं हो जाता।
स्टीवन एवर्स

@ साइन: दोनों आपने क्या कहा और स्नोरफस ने क्या कहा। या अगर मैं किसी संपत्ति में परिवर्तन लॉग करना चाहता हूं, तो मैं प्रारंभिक सेटिंग लॉग नहीं करना चाहता। लेकिन, मैंने कहा "आम तौर पर"।
पितृ पक्ष

3
@ संकेत: समस्या यह है: यदि संपत्ति के सेट विधि को एक उपवर्ग में ओवरराइड किया जा सकता है, तो आप ऑब्जेक्ट के निर्माण या एक असंगत वस्तु के दौरान दुष्प्रभाव हो सकते हैं (यानी: ओवरराइड की गई संपत्ति के लिए कोई मूल्य निर्धारित नहीं किया जाता है; वह मैदान)। यदि सेट विधि निजी है या वर्ग सील है, तो कंस्ट्रक्टर्स में गुणों का उपयोग करना सुरक्षित है।
डिएगो

4

निर्भर करता है।

पहले आपको जब संभव हो तो स्वचालित गुणों को प्राथमिकता देनी चाहिए:

public string MyValue {get;set;}

दूसरा बेहतर तरीका शायद गुणों का उपयोग करना होगा, यदि आपके पास कोई तर्क है तो आपको संभवतः खुद से गुजरना चाहिए, खासकर यदि वह तर्क थ्रेड सिंक्रोनाइज़ेशन है।

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


3
मुझे भी पसंद है public string MyValue {get; private set;}
नौकरी

3

ठीक है, सीधे-टू-द-पॉइंट दृष्टिकोण केवल चर के लिए इसे असाइन करना होगा, क्योंकि आप एक वर्ग विधि के अंदर हैं और आप कक्षा के व्यवहार को वैसे भी नियंत्रित करते हैं।

लेकिन गुणों के बारे में पूरी बात यह है कि वे चर को दूर करते हैं। जबकि आपके उदाहरण में इस तरह की एक साधारण संपत्ति का सिर्फ एक साधारण सार्वजनिक सदस्य चर पर पूरी तरह से कोई उपयोग नहीं है, गुण आमतौर पर अपने गेटर्स और बसने वालों के अंदर अतिरिक्त चीजें करते हैं (या करना चाहिए)। और यदि आप चाहते हैं कि क्लास के अंदर प्रॉपर्टी बदलते समय ये चीजें अपने आप हो जाएं, तो प्रॉपर्टी पर काम करने के लिए प्रॉपर्टी पर काम करना क्लीनर की तरह है, प्रॉपर्टी सेटिंग बिहेवियर में बदलाव होने पर हर वैरिएबल असाइनमेंट को बदलना नहीं है।

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


2

यदि कोई मौका है कि उन संपत्ति को प्राप्त / सेट कार्यान्वयन कभी-कभी बाद में बदल जाएगा (उदाहरण के लिए, आप कॉल करते समय किसी घटना को बढ़ाना चाहते हैं set, या आप अपने getकार्य के लिए बाद में कुछ आलसी मूल्यांकन तंत्र जोड़ देंगे ), तो यह एक अच्छा विचार हो सकता है वर्ग के अंदर आपका कोड संपत्ति को लगभग सभी मामलों में उपयोग करेगा - सिवाय शायद दुर्लभतम मामलों में - जहाँ आप स्पष्ट रूप से उन घटनाओं या आलसी मूल्यांकन तंत्र का उपयोग नहीं करना चाहते हैं।

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


2

मैं हमेशा सार्वजनिक संपत्ति का उपयोग करता हूं।

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

आपके पास इस प्रश्न के लिए MVVM के बारे में एक टिप्पणी है, और मुझे लगता है कि MVVM के साथ काम करते समय यह और भी महत्वपूर्ण है। कई ऑब्जेक्ट PropertyChangeसेटर को एक सूचना देते हैं, और अन्य ऑब्जेक्ट विशिष्ट गुण बदलने पर कुछ कार्रवाई को निष्पादित करने के लिए इस घटना की सदस्यता ले सकते हैं। यदि आप निजी चर सेट करते हैं, तो ये क्रियाएं कभी भी निष्पादित नहीं होंगी जब तक कि आप मैन्युअल रूप से PropertyChangedघटना को नहीं बढ़ाते ।


+1 अधिकांश मामलों में (MVVM) प्रॉपर्टीचेंज इवेंट एक जरूरी है। और वह केवल एक संपत्ति के अंदर निकाल दिया जा सकता है। अच्छे खर्च।
एडवर्ड

1

आम तौर पर, यह आपके ऊपर होता है कि आपको प्रॉपर्टी और उसके बैकिंग क्षेत्र के साथ क्या करना चाहिए / प्राप्त करते समय।

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

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


0

हमेशा उसी का उपयोग करें जो समझ में आता है। हां, मुझे पता है कि एक गैर-उत्तर होने की बात करने के लिए बहुत ही अजीब लगता है।

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

public Foo Bar
{
  get { return _bar; }
  set { _bar = doSomethingTo(value); }
}

लेकिन अन्य स्थितियों में, आप बस एक संपत्ति का उपयोग डेटा मॉडल के रूप में कर सकते हैं:

public Double SomeAngleDegrees
{
  get { return SomeAngleRadians * 180 / PI; }
  set { SomeAngleRadians = value * PI / 180; }
}

अगर यह रेडियन रूप का उपयोग करने के लिए समझ में आता है SomeAngle, तो हर तरह से इसका उपयोग करें।

अंत में, अपनी खुद की कूल-एड पीना सुनिश्चित करें। आपके सार्वजनिक रूप से सामना करने वाली एपी को आंतरिक रूप से काम करने के लिए पर्याप्त लचीला होना चाहिए।

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