मुझे C # में गुण का उपयोग करने से क्यों बचना चाहिए?


102

अपनी उत्कृष्ट पुस्तक, सीएलआर वाया सी # में, जेफरी रिक्टर ने कहा कि वह गुणों को पसंद नहीं करता है, और उनका उपयोग नहीं करने की सिफारिश करता है। उन्होंने कुछ कारण दिया, लेकिन मैं वास्तव में नहीं समझता। क्या कोई मुझे समझा सकता है कि मुझे संपत्तियों का उपयोग क्यों करना चाहिए या नहीं करना चाहिए? C # 3.0 में, स्वचालित गुणों के साथ, क्या यह बदलता है?

एक संदर्भ के रूप में, मैंने जेफरी रिक्टर की राय को जोड़ा:

• एक संपत्ति केवल-पढ़ने या केवल लिखने के लिए हो सकती है; क्षेत्र की पहुंच हमेशा पठनीय और लेखन योग्य होती है। यदि आप किसी संपत्ति को परिभाषित करते हैं, तो एक्सेसर के तरीकों को प्राप्त करना और सेट करना दोनों की पेशकश करना सबसे अच्छा है।

• एक संपत्ति विधि एक अपवाद फेंक सकती है; फ़ील्ड एक्सेस कभी भी अपवाद नहीं होता है।

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

using System;
public sealed class SomeType
{
   private static String Name 
   {
     get { return null; }
     set {}
   }
   static void MethodWithOutParam(out String n) { n = null; }
   public static void Main()
   {
      // For the line of code below, the C# compiler emits the following:
      // error CS0206: A property or indexer may not
      // be passed as an out or ref parameter
      MethodWithOutParam(out Name);
   }
}

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

• यदि एक पंक्ति में कई बार कहा जाता है, तो एक संपत्ति विधि हर बार एक अलग मान लौटा सकती है; एक फ़ील्ड हर बार समान मूल्य देता है। System.DateTime वर्ग के पास एक रीडोनॉली नाउ प्रॉपर्टी है जो वर्तमान दिनांक और समय लौटाती है। हर बार जब आप इस प्रॉपर्टी को क्वेरी करते हैं, तो यह एक अलग मूल्य लौटाएगा। यह एक गलती है, और Microsoft की इच्छा है कि वे संपत्ति के बजाय अब एक विधि बनाकर वर्ग को ठीक कर सकते हैं।

• एक संपत्ति विधि के कारण दुष्प्रभाव हो सकते हैं; फ़ील्ड एक्सेस कभी नहीं करता है। दूसरे शब्दों में, एक प्रकार का उपयोगकर्ता किसी भी क्रम में एक प्रकार से परिभाषित विभिन्न गुणों को निर्धारित करने में सक्षम होना चाहिए, वह किसी भी प्रकार के किसी भी व्यवहार को नोट किए बिना चुनता है।

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


11
मैं 'सीएलआर के माध्यम से सीएलआर' के तीसरे संस्करण का मालिक हूं और पृष्ठ 242 पर श्री रिक्टर कहते हैं कि उन्हें व्यक्तिगत रूप से संपत्ति पसंद नहीं है, लेकिन वह कभी भी उनका उपयोग नहीं करने की सलाह देते हैं। कृपया पुस्तक संस्करण और पृष्ठ संख्या का हवाला दें जहाँ आप इसे पढ़ते हैं।
kirk.burleson

जवाबों:


173

गुणों को नापसंद करने के लिए जेफ का कारण यह है कि वे खेतों की तरह दिखते हैं - इसलिए डेवलपर्स जो अंतर को नहीं समझते हैं वे उन्हें मानेंगे जैसे कि वे क्षेत्र हैं, यह मानते हुए कि वे निष्पादित करने के लिए सस्ते होंगे।

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

(और नहीं, स्वचालित रूप से कार्यान्वित गुण वास्तव में इसमें से किसी को भी नहीं बदलते हैं।)

यह विस्तार के तरीकों का उपयोग करने के खिलाफ तर्कों की तरह है - मैं तर्क को समझ सकता हूं, लेकिन व्यावहारिक लाभ (जब संयम से इस्तेमाल किया जाता है) तो मेरे विचार में नकारात्मक पक्ष को छोड़ देता है।


आप जवाब के लिए बहुत बहुत धन्यवाद! विस्तार विधियों का उपयोग करने के खिलाफ तर्क के बारे में: क्या आप कुछ जेफरी रिक्टर के विषय या सार में बात कर रहे हैं?
abatishchev

@abatishchev: यह विस्तार के तरीकों के बारे में एक सामान्य बिंदु था। यह सीधे गुणों से संबंधित नहीं है।
जॉन स्कीट

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

1
@PatrickFromberg: आपने कोड की एक बड़ी मात्रा को याद किया है जो केवल-पढ़ने के लिए फ़ील्ड का उपयोग करता है। यह कहने के लिए कुछ भी नहीं है कि गुण उत्परिवर्तन को कहते हैं। मेरे पास अक्सर रीड-ओनली प्रॉपर्टी के लिए रीड-ओनली फील्ड्स होते हैं - क्या आपको लगता है कि यह एक बुरी बात है?
जॉन स्कीट

1
@ पैट्रिक: नहीं, यह कार्यान्वयन से एपीआई को अलग करने का लाभ लाता है - आप बाद में बदल सकते हैं कि संपत्ति को फ़ील्ड से कैसे गणना की जाती है (जैसे एक क्षेत्र से दो संबंधित गुणों की गणना करना)।
जॉन स्कीट

34

अच्छा, एक-एक करके अपने तर्क दें:

एक संपत्ति केवल-पढ़ने या केवल लिखने के लिए हो सकती है; क्षेत्र की पहुंच हमेशा पठनीय और लेखन योग्य होती है।

यह गुणों की जीत है, क्योंकि आपके पास पहुंच का अधिक सूक्ष्म नियंत्रण है।

एक संपत्ति विधि एक अपवाद फेंक सकती है; फ़ील्ड एक्सेस कभी भी अपवाद नहीं होता है।

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

• एक संपत्ति एक विधि के लिए एक बाहर या रेफरी पैरामीटर के रूप में पारित नहीं किया जा सकता है; एक क्षेत्र कर सकते हैं।

मेला।

• एक संपत्ति विधि को निष्पादित करने में लंबा समय लग सकता है; फ़ील्ड एक्सेस हमेशा तुरंत पूरा होता है।

इसमें बहुत कम समय भी लग सकता है।

• यदि एक पंक्ति में कई बार कहा जाता है, तो एक संपत्ति विधि हर बार एक अलग मान लौटा सकती है; एक फ़ील्ड हर बार समान मूल्य देता है।

सच नहीं। आपको कैसे पता चलेगा कि क्षेत्र का मूल्य नहीं बदला है (संभवतः दूसरे धागे से)?

System.DateTime वर्ग के पास एक रीडोनॉली नाउ प्रॉपर्टी है जो वर्तमान दिनांक और समय लौटाती है। हर बार जब आप इस प्रॉपर्टी को क्वेरी करते हैं, तो यह एक अलग मूल्य लौटाएगा। यह एक गलती है, और Microsoft की इच्छा है कि वे संपत्ति के बजाय अब एक विधि बनाकर वर्ग को ठीक कर सकते हैं।

यदि यह एक गलती है तो यह एक छोटी सी बात है।

• एक संपत्ति विधि के कारण दुष्प्रभाव हो सकते हैं; फ़ील्ड एक्सेस कभी नहीं करता है। दूसरे शब्दों में, एक प्रकार का उपयोगकर्ता किसी भी क्रम में एक प्रकार से परिभाषित विभिन्न गुणों को निर्धारित करने में सक्षम होना चाहिए, वह किसी भी प्रकार के किसी भी व्यवहार को नोट किए बिना चुनता है।

मेला।

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

अधिकांश विरोध प्रदर्शन जावा के गेटर्स के लिए कहा जा सकता है और बसने के लिए भी - और व्यवहार में ऐसी समस्याओं के बिना हम उनके पास काफी समय से थे।

मुझे लगता है कि ज्यादातर समस्याओं को बेहतर सिंटैक्स हाइलाइटिंग (यानी खेतों से अलग गुण) द्वारा हल किया जा सकता है, इसलिए प्रोग्रामर जानता है कि क्या उम्मीद है।


3
"समस्याओं को बेहतर सिंटैक्स हाइलाइटिंग द्वारा हल किया जा सकता है" : आप कितनी बार सार्वजनिक क्षेत्रों का उपयोग करते हैं? निजी क्षेत्रों में आमतौर पर एक अलग शैली होती है, जैसे _field। या बस भी कम field
स्टीवन ज्यूरिस

18

मैंने पुस्तक नहीं पढ़ी है, और आपने इसके भाग को उद्धृत नहीं किया है जिसे आप नहीं समझते हैं, इसलिए मुझे अनुमान लगाना होगा।

कुछ लोग गुणों को नापसंद करते हैं क्योंकि वे आपके कोड को आश्चर्यजनक तरीके से कर सकते हैं।

यदि मैं टाइप करता हूं Foo.Bar, तो इसे पढ़ने वाले लोग सामान्य रूप से उम्मीद करेंगे कि यह बस फू वर्ग के सदस्य क्षेत्र तक पहुंच रहा है। यह एक सस्ता, लगभग मुफ्त, ऑपरेशन है, और यह नियतात्मक है। मैं इसे बार-बार कॉल कर सकता हूं, और हर बार एक ही परिणाम प्राप्त कर सकता हूं।

इसके बजाय, गुणों के साथ, यह वास्तव में एक फ़ंक्शन कॉल हो सकता है। यह एक अनंत लूप हो सकता है। यह एक डेटाबेस कनेक्शन खोल सकता है। हर बार जब मैं इसे एक्सेस करता हूं तो यह अलग-अलग मान लौटा सकता है।

यह एक समान तर्क है कि लिनुस C ++ से नफरत क्यों करता है। आपका कोड पाठक को आश्चर्यचकित कर सकता है। वह ऑपरेटर को ओवरलोडिंग से नफरत करता है: a + bजरूरी नहीं कि इसके अतिरिक्त सरल हो। इसका मतलब कुछ हद तक जटिल ऑपरेशन हो सकता है, जैसे सी # गुण। इसके दुष्प्रभाव हो सकते हैं। यह कुछ भी कर सकता है।

ईमानदारी से, मुझे लगता है कि यह एक कमजोर तर्क है। दोनों भाषाएं इस तरह से भरी हुई हैं। (क्या हमें ऑपरेटर को C # में ओवरलोडिंग से बचना चाहिए? आखिरकार, एक ही तर्क का इस्तेमाल किया जा सकता है)

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

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

हालांकि, मेरे पास उन्हें सही से कम खोजने का एक और कारण है। उन्हें अन्य कार्यों के संदर्भ में पारित नहीं किया जा सकता है।

फ़ील्ड्स को पास किया जा सकता है ref, जो किसी फ़ंक्शन को सीधे इसे एक्सेस करने की अनुमति देता है। फ़ंक्शंस को प्रतिनिधियों के रूप में पारित किया जा सकता है, जो एक फ़ंक्शन को सीधे इसे एक्सेस करने की अनुमति देता है।

गुण ... नहीं कर सकते।

वह चूसता है।

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


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

1
हाँ मै सह्मत हूँ। यह तर्क "मुझे लगता है कि इस वाक्यविन्यास का उपयोग केवल खेतों के लिए किया जा रहा है। इसलिए, अन्य मामलों को कवर करने के लिए इसका विस्तार करना बुरा है"। और स्पष्ट उत्तर है "ठीक है, इसे अन्य मामलों को कवर करने की आदत डालें, और यह बुरा नहीं होगा"। ;)
जल्प

मेरी इच्छा है कि .net भाषाएँ एक मानक साधन प्रदान करती हैं जिसके द्वारा एक वर्ग ने गुणों को refपरम के रूप में उजागर किया है ; एक सदस्य का (जैसे Foo) void Foo<T>(ActionByRef<Point,T> proc, ref T param)एक विशेष विशेषता के साथ एक फार्म , और संकलक में तब्दील thing.Foo.X+=someVar;है Foo((ref Point it, ref int param)=>it.X += param, ref someVar);। चूंकि लैम्ब्डा एक स्टैटिक डेलीगेट है, इसलिए किसी क्लोजर की आवश्यकता नहीं होगी, और किसी ऑब्जेक्ट के उपयोगकर्ता को जो भी स्टोरेज लोकेशन प्रॉपर्टी को वास्तविक refपैरामीटर के रूप में उपयोग करने में सक्षम होगा (और इसे एक refपैरामीटर के रूप में अन्य तरीकों से पास कर सकता है )।
सुपरकैट

हाथ से लैम्ब्डा लिखना वास्तव में icky- दिखने वाले स्रोत कोड का उत्पादन करता है, लेकिन यही कारण है कि संकलक प्रदर्शन को बदलने में मददगार होगा। "कॉलबैक-बाय-रेफ" संपत्ति को उजागर करने के लिए एक वर्ग के लिए कोड बहुत ही उचित होगा। कॉलर की ओर कोड का केवल बदसूरत (एक परिवर्तन अनुपस्थित)।
सुपरकैट

कृपया समझें कि एक संपत्ति एक सदस्य के रूप में प्रच्छन्न एक फ़ंक्शन कॉल है, इसलिए इसे किसी भी वर्ग के सार्वजनिक कार्यों को पारित करने से अधिक किसी भी संदर्भ में पारित नहीं किया जा सकता है। आप हमेशा सार्वजनिक सदस्य का उपयोग कर सकते हैं यदि आप इसे इस तरह से करने का इरादा रखते हैं। एक संपत्ति एक स्मार्ट सदस्य है, यह सेट करने के लिए पारित अवैध डेटा के लिए एक अपवाद फेंक सकता है।
डाइसियस

17

2009 में वापस, यह सलाह महज मेरी चीज़ किस्म को हटाने की तरह लग रही थी । आज, यह लगभग हंसमुख है।

एक बहुत ही महत्वपूर्ण बिंदु है कि बहुत से उत्तर चारों ओर से स्पष्ट प्रतीत होते हैं, लेकिन इस बात पर काफी ध्यान नहीं दिया जाता है कि संपत्तियों के ये कथित "खतरे" फ्रेमवर्क डिजाइन का एक जानबूझकर हिस्सा हैं!

हाँ, गुण कर सकते हैं:

  • गेट्टर और सेटर के लिए अलग-अलग एक्सेस मॉडिफायर निर्दिष्ट करें। यह खेतों पर एक फायदा है । एक सामान्य पैटर्न में एक सार्वजनिक गेट्टर और एक संरक्षित या आंतरिक सेटर है, एक बहुत ही उपयोगी विरासत तकनीक है जो अकेले खेतों के लिए प्राप्त नहीं है।

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

  • निष्पादित करने के लिए एक लंबा समय लें। यहां वैध तुलना विधियों के साथ है , जो समान रूप से लंबे समय तक ले जाती हैं - फ़ील्ड नहीं । किसी लेखक की व्यक्तिगत पसंद के अलावा "किसी विधि को प्राथमिकता दी जाती है" कथन के लिए कोई आधार नहीं दिया गया है।

  • बाद के निष्पादन पर इसके गेटर से अलग मान लौटाएँ। यह लगभग फ़ील्ड के साथ ref/ outमापदंडों के गुणों को बाहर निकालने वाले बिंदु के इतने करीब निकटता में एक मजाक की तरह लगता है , जिसका ref/ outकॉल के बाद किसी फ़ील्ड का मान उसके पिछले मूल्य से अलग होने की बहुत गारंटी है, और अप्रत्याशित रूप से।

    यदि हम विशिष्ट अभिभावकों के साथ एकल-पिरोया अभिगम के विशिष्ट (और व्यावहारिक रूप से अकादमिक) मामले के बारे में बात कर रहे हैं, तो यह काफी हद तक समझ में आ गया है कि यह दृश्य-राज्य-बदलते साइड-इफेक्ट्स के लिए सिर्फ खराब संपत्ति डिजाइन है, और शायद मेरी स्मृति है लुप्त होती है, लेकिन मैं DateTime.Nowहर बार आने वाले समान मूल्य का उपयोग करने और उम्मीद करने वाले लोगों के किसी भी उदाहरण को याद नहीं कर सकता । कम से कम कोई उदाहरण नहीं जहां उन्होंने इसे खराब नहीं किया होगा, केवल एक काल्पनिक के साथ DateTime.Now()

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

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

अन्य चीजें जो गुण कर सकती हैं वे कौन से क्षेत्र शामिल नहीं कर सकते हैं:

  • आलसी लोडिंग , आरंभीकरण-क्रम त्रुटियों को रोकने के सबसे प्रभावी तरीकों में से एक।
  • परिवर्तन सूचनाएँ , जो MVVM वास्तुकला के लिए संपूर्ण आधार हैं ।
  • वंशानुक्रम , उदाहरण के लिए एक अमूर्त Typeया Nameव्युत्पन्न वर्ग को परिभाषित करने से अपने बारे में दिलचस्प लेकिन फिर भी निरंतर मेटाडेटा प्रदान किया जा सकता है।
  • अवरोधन , उपरोक्त के लिए धन्यवाद।
  • इंडेक्सर्स , जो हर किसी को कभी COM इंटरॉप के साथ काम करना पड़ता है और Item(i)कॉल के अपरिहार्य स्प्यू को एक अद्भुत चीज के रूप में पहचाना जाएगा।
  • प्रॉपर्टीस्क्रिप्ट के साथ काम करना जो डिजाइनरों को बनाने और सामान्य रूप से एक्सएएमएल फ्रेमवर्क के लिए आवश्यक है।

रिक्टर स्पष्ट रूप से एक विपुल लेखक है और सीएलआर और सी # के बारे में बहुत कुछ जानता है, लेकिन मुझे यह कहना है, ऐसा लगता है जब उसने मूल रूप से यह सलाह लिखी है (मुझे यकीन नहीं है कि यह उसके हाल के संशोधनों में है - मुझे पूरी उम्मीद है कि नहीं) वह केवल पुरानी आदतों को जाने नहीं देना चाहता था और सी # (उदाहरण के लिए सी ++) के सम्मेलनों को स्वीकार करने में परेशानी हो रही थी।

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

C # में दो बहुत मजबूत कोडिंग कन्वेंशन हैं जो अन्य सीएलआर भाषाओं द्वारा साझा किए गए समान सम्मेलनों के साथ हैं, और यदि आप उनका पालन नहीं करते हैं तो FXCop आपको चिल्लाएगी:

  1. फील्ड हमेशा निजी होनी चाहिए , सार्वजनिक नहीं
  2. कैमलकेस में फ़ील्ड घोषित किया जाना चाहिए। गुण PascalCase हैं।

इस प्रकार, इस बात पर कोई अस्पष्टता नहीं है कि Foo.Bar = 42संपत्ति का एक्सेसर या फील्ड एक्सेसर है या नहीं। यह एक प्रॉपर्टी एक्सेसर है और इसे किसी अन्य तरीके की तरह माना जाना चाहिए - यह धीमा हो सकता है, यह एक अपवाद फेंक सकता है, आदि। यह एब्सट्रैक्शन की प्रकृति है - यह पूरी तरह से घोषित वर्ग के विवेक पर निर्भर है कि कैसे प्रतिक्रिया दें। क्लास डिजाइनरों को कम से कम आश्चर्य के सिद्धांत को लागू करना चाहिए लेकिन कॉल करने वालों को किसी संपत्ति के बारे में कुछ भी नहीं मानना ​​चाहिए, सिवाय इसके कि वह टिन पर क्या कहता है। यह उद्देश्य पर है।

गुणों का विकल्प हर जगह गेटर / सेटर विधियां हैं। यह जावा दृष्टिकोण है, और यह शुरुआत से ही विवादास्पद रहा है । यदि आपका बैग ठीक है तो यह ठीक है, लेकिन यह ठीक नहीं है कि हम .NET कैंप में कैसे रोल करते हैं। हम कोशिश करते हैं कि कम से कम एक स्टेटिक-टाइप सिस्टम की सीमा के भीतर, इससे बचने के लिए कि फाउलर को सिनेटिक शोर कहते हैं । हम अतिरिक्त कोष्ठक, अतिरिक्त get/ setमौसा, या अतिरिक्त विधि हस्ताक्षर नहीं चाहते हैं - यदि हम स्पष्टता के किसी भी नुकसान के बिना उनसे बच नहीं सकते।

आप जो चाहें कहें, लेकिन foo.Bar.Baz = quux.Answers[42]हमेशा पढ़ने में बहुत आसान होने जा रहा है foo.getBar().setBaz(quux.getAnswers().getItem(42))। और जब आप एक दिन में हजारों लाइनों को पढ़ रहे होते हैं, तो इससे फर्क पड़ता है।

(और अगर उपरोक्त पैराग्राफ के लिए आपकी स्वाभाविक प्रतिक्रिया है, "निश्चित रूप से पढ़ना मुश्किल है, लेकिन यह आसान होगा यदि आप इसे कई लाइनों में विभाजित करते हैं", तो मुझे यह कहने के लिए खेद है कि आप पूरी तरह से चूक गए हैं ।)


11

मुझे ऐसे कोई कारण नहीं दिखाई देते हैं कि आपको प्रॉपर्टी का सामान्य रूप से उपयोग क्यों नहीं करना चाहिए।

C # 3+ में स्वचालित गुण केवल वाक्यविन्यास को थोड़ा सरल करते हैं (एक ला सिन्थेटिक चीनी)।


कृपया, उस पुस्तक में पृष्ठ २१५-२१६ पढ़ें। मुझे यकीन है कि आप जानते हैं कि जेफरी रिक्टर कौन है!
क्वान माई

मैंने पढ़ा है (C #, 2nd Ed। के माध्यम से CLR), उसकी स्थिति से सहमत नहीं हैं और यह नहीं देखते हैं कि वास्तविक कारण गुणों का उपयोग नहीं करते हैं!
abatishchev

यह एक अच्छी किताब है, लेकिन मैं इस क्षण में लेखक से सहमत नहीं हूं।
कॉन्सटेंटिन टर्कस

वास्तव में वह जगह कहां है जहां लेखक गुण का उपयोग नहीं करने का सुझाव देता है? P.215-217 पर कुछ भी नहीं मिला है
कॉन्सटेंटिन

मैंने अपने सवाल में जेफरी की राय जोड़ी :)। आप इसे पृष्ठ 215-216 में प्रिंट संस्करण में देख सकते हैं :)
क्वान माई

9

यह सिर्फ एक व्यक्ति की राय है। मैंने काफी सी # किताबें पढ़ी हैं और मुझे अभी तक किसी और को यह कहते हुए नहीं देखना है कि "गुणों का उपयोग न करें"।

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

गुणों के साथ गुहाओं के लिए, एक जोड़े हैं। एक शायद गुणों का दुरुपयोग है, दूसरा सूक्ष्म हो सकता है।

सबसे पहले, गुण विधियों के प्रकार हैं। यदि आप किसी संपत्ति में जटिल तर्क रखते हैं तो यह आश्चर्य की बात हो सकती है क्योंकि एक वर्ग के अधिकांश उपयोगकर्ता संपत्ति के काफी हल्के होने की उम्मीद करेंगे।

उदाहरण के लिए

public class WorkerUsingMethod
{
   // Explicitly obvious that calculation is being done here
   public int CalculateResult()
   { 
      return ExpensiveLongRunningCalculation();
   }
}

public class WorkerUsingProperty
{
   // Not at all obvious.  Looks like it may just be returning a cached result.
   public int Result
   {
       get { return ExpensiveLongRunningCalculation(); }
   }
}

मुझे लगता है कि इन मामलों के लिए तरीकों का उपयोग करने से भेद बनाने में मदद मिलती है।

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

कहो कि आपके पास कुछ संपत्ति है:

public int Result 
{ 
   get 
   { 
       m_numberQueries++; 
       return m_result; 
   } 
}

अब मान लें कि आपके पास एक अपवाद है जो तब होता है जब बहुत सारे प्रश्न किए जाते हैं। लगता है कि क्या होता है जब आप डिबगिंग शुरू करते हैं और डीबगर में संपत्ति को रोलओवर करते हैं? बुरी चीजें। ऐसा करने से बचें! संपत्ति को देखकर कार्यक्रम की स्थिति बदल जाती है।

मेरे पास केवल ये कैविएट हैं। मुझे लगता है कि गुणों के लाभ समस्याओं को दूर करते हैं।


6

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


ग्राहक और वर्ग की संपत्ति के बीच "अनुबंध" के महत्व को स्पष्ट रूप से उजागर करने के लिए +1।
TheBlastOne

6

मैं जेफरी रिक्टर की राय का विवरण लेने में मदद नहीं कर सकता:

एक संपत्ति केवल-पढ़ने या केवल लिखने के लिए हो सकती है; क्षेत्र की पहुंच हमेशा पठनीय और लेखन योग्य होती है।

गलत: फ़ील्ड केवल पढ़ने के लिए चिह्नित की जा सकती हैं, इसलिए केवल ऑब्जेक्ट का निर्माता ही उन्हें लिख सकता है।

एक संपत्ति विधि एक अपवाद फेंक सकती है; फ़ील्ड एक्सेस कभी भी अपवाद नहीं होता है।

गलत: एक वर्ग के कार्यान्वयन से सार्वजनिक से निजी तक एक क्षेत्र का उपयोग संशोधक बदल सकता है। निजी क्षेत्रों को रनटाइम पर पढ़ने का प्रयास हमेशा एक अपवाद के रूप में होगा।


5

मैं जेफरी रिक्टर के साथ सहमत नहीं हूं, लेकिन मैं अनुमान लगा सकता हूं कि वह संपत्तियों को क्यों पसंद नहीं करता (मैंने उसकी किताब नहीं पढ़ी है)।

भले ही, गुण सिर्फ तरीकों (कार्यान्वयन-वार) की तरह हैं, एक वर्ग के उपयोगकर्ता के रूप में, मुझे उम्मीद है कि इसके गुण सार्वजनिक क्षेत्र की तरह "अधिक या कम" व्यवहार करते हैं, जैसे:

  • प्रॉपर्टी गेट्टर / सेटर के अंदर कोई समय लेने वाला ऑपरेशन नहीं चल रहा है
  • संपत्ति पाने वाले के पास कोई साइड इफेक्ट नहीं है (इसे कई बार कॉल करना, परिणाम नहीं बदलता है)

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


1
+1 चूंकि यह एक स्वच्छ अनुबंध के महत्व पर प्रकाश डालता है। प्रतीत होता है आसानी से संपत्ति जो नियमित रूप से प्रत्येक संदर्भ पर एक अलग मूल्य देता है एक readwrite संपत्ति है - यह सिर्फ अपने मूल्य पर नहीं लिखता है, लेकिन अन्य उदाहरण चर (प्रत्यक्ष या अप्रत्यक्ष रूप से)। यह खराब शैली नहीं है, लेकिन दस्तावेज होना चाहिए (या अनुबंध का एक अंतर्निहित हिस्सा होना चाहिए)।
TheBlastOne

4

एक समय है जब मैं गुणों का उपयोग नहीं करने पर विचार करता हूं, और वह लिखित रूप में है। नेट कॉम्पैक्ट फ्रेमवर्क कोड। CF JIT कंपाइलर डेस्कटॉप JIT कंपाइलर के समान ऑप्टिमाइज़ेशन नहीं करता है और सिंपल प्रॉपर्टी एक्सेसर्स को ऑप्टिमाइज़ नहीं करता है, इसलिए इस मामले में एक सिंपल प्रॉपर्टी को जोड़ने से पब्लिक फील्ड का इस्तेमाल करने पर कम मात्रा में कोड ब्लाट होता है। आमतौर पर यह एक मुद्दा नहीं होगा, लेकिन लगभग हमेशा कॉम्पैक्ट फ्रेमवर्क की दुनिया में आप तंग मेमोरी बाधाओं के खिलाफ हैं, इसलिए इस तरह की गिनती से भी छोटी बचत होती है।


4

आपको उनका उपयोग करने से बचना चाहिए लेकिन अन्य योगदानकर्ताओं द्वारा दिए गए कारणों से आपको उन्हें योग्यता और देखभाल के साथ उपयोग करना चाहिए।

मैंने एक बार ग्राहकों की तरह एक संपत्ति देखी, जिसे आंतरिक रूप से एक डेटाबेस में एक आउट-ऑफ-प्रोसेस कॉल खोला और ग्राहक सूची को पढ़ा। क्लाइंट कोड में 'for (int i to customers.Count)' था, जो डेटाबेस के प्रत्येक पुनरावृत्ति पर और चयनित ग्राहक की पहुँच के लिए एक अलग कॉल का कारण बन रहा था। यह एक बड़ा उदाहरण है जो संपत्ति को बहुत हल्का रखने के सिद्धांत को प्रदर्शित करता है - शायद ही कभी एक आंतरिक क्षेत्र पहुंच से अधिक है।

गुणों का उपयोग करने के लिए एक तर्क यह है कि वे आपको निर्धारित मूल्य को मान्य करने की अनुमति देते हैं। एक और यह है कि संपत्ति का मूल्य एक व्युत्पन्न मूल्य हो सकता है, कुल फ़ील्ड नहीं, जैसे TotalValue = राशि * मात्रा।


3

व्यक्तिगत रूप से मैं केवल संपत्तियों का उपयोग करता हूं जब सरल गेट / सेट विधियां बनाते हैं। जटिल डेटा संरचनाओं में आने पर मैं इससे दूर भटक जाता हूं।


3

तर्क मानता है कि गुण खराब हैं क्योंकि वे खेतों की तरह दिखते हैं, लेकिन आश्चर्यजनक कार्रवाई कर सकते हैं। यह धारणा .NET प्रोग्रामर की अपेक्षाओं द्वारा अमान्य है:

गुण फ़ील्ड की तरह नहीं दिखते हैं। फ़ील्ड गुण के समान दिखते हैं।

• एक संपत्ति विधि एक अपवाद फेंक सकती है; फ़ील्ड एक्सेस कभी भी अपवाद नहीं होता है।

इसलिए, एक फ़ील्ड एक संपत्ति की तरह है जिसे कभी भी अपवाद नहीं फेंकने की गारंटी दी जाती है।

• एक संपत्ति एक विधि के लिए एक बाहर या रेफरी पैरामीटर के रूप में पारित नहीं किया जा सकता है; एक क्षेत्र कर सकते हैं।

इसलिए, एक क्षेत्र एक संपत्ति की तरह है, लेकिन इसमें अतिरिक्त क्षमताएं हैं: एक ref/ outस्वीकार करने के तरीकों से गुजरना ।

• एक संपत्ति विधि को निष्पादित करने में लंबा समय लग सकता है; फ़ील्ड एक्सेस हमेशा तुरंत पूरा होता है। [...]

तो, एक क्षेत्र एक तेज संपत्ति की तरह है।

• यदि एक पंक्ति में कई बार कहा जाता है, तो एक संपत्ति विधि हर बार एक अलग मान लौटा सकती है; एक फ़ील्ड हर बार समान मूल्य देता है। System.DateTime वर्ग के पास एक रीडोनॉली नाउ प्रॉपर्टी है जो वर्तमान दिनांक और समय लौटाती है।

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

• एक संपत्ति विधि के कारण दुष्प्रभाव हो सकते हैं; फ़ील्ड एक्सेस कभी नहीं करता है।

फिर से, एक क्षेत्र एक संपत्ति है जो ऐसा नहीं करने की गारंटी है।

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

यह आश्चर्य की बात हो सकती है, लेकिन इसलिए नहीं कि यह ऐसा गुण है जो ऐसा करता है। बल्कि, यह है कि बमुश्किल कोई भी संपत्तियों में परिवर्तनशील प्रतियां लौटाता है, जिससे 0.1% मामला आश्चर्यचकित करता है।


0

गुणों के बजाय तरीकों को लागू करने से कोड को लागू करने की पठनीयता बहुत कम हो जाती है। J # में, उदाहरण के लिए, ADO.NET का उपयोग करना एक बुरा सपना था क्योंकि जावा गुण और अनुक्रमणिका (जो अनिवार्य रूप से तर्क के साथ गुण हैं) का समर्थन नहीं करता है। परिणामी कोड बेहद बदसूरत था, जिसमें खाली कोष्ठक विधि सभी जगह कॉल करती थी।

प्रॉपर्टीज और इंडेक्सर्स का समर्थन जावा पर C # के मूल लाभों में से एक है।

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