2010-10-12 7 views
54

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

मैं दो तरीकों से यह करने के लिए देखें:

  1. class MyClass 
    { 
        public readonly object MyProperty = new object(); 
    } 
    
  2. class MyClass 
    { 
        private readonly object my_property = new object(); 
        public object MyProperty { get { return my_property; } } 
    } 
    

इन सब FxCop त्रुटियों कह रही है कि मैं सार्वजनिक सदस्य चर नहीं करना चाहिए था, ऐसा लगता है कि एक दूसरे के ऐसा करने का सही तरीका है। सही बात?

क्या केवल एक संपत्ति प्राप्त करने और इस मामले में केवल पढ़ने वाले सदस्य के बीच कोई अंतर है?

मैं किसी भी टिप्पणी/सलाह/आदि की सराहना करता हूं।

+20

मैं कभी-कभी ऑटो-प्रॉपर्टी सिंटैक्स को 'प्राप्त करने की इच्छा करता हूं; केवल पढ़ने के लिए सेट; 'विकल्प। –

+0

[सी #, अपरिवर्तनीयता और सार्वजनिक रीडोनली फ़ील्ड] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/2249980/c-immutability-and-public-readonly-fields) – user

उत्तर

31

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

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

क्रमबद्धता
संपत्ति के क्षेत्र से बदल रहा है शायद serializers का एक बहुत टूट जाएगा। और AFAIK XmlSerializer केवल सार्वजनिक गुणों को क्रमबद्ध करता है, न कि सार्वजनिक फ़ील्ड।

एक Autoproperty
एक अन्य आम परिवर्तन का उपयोग एक निजी सेटर के साथ एक autoproperty उपयोग कर रहा है। हालांकि यह छोटा है और एक संपत्ति यह पठनीयता को लागू नहीं करती है। तो मैं दूसरे को पसंद करता हूं।

केवल पढ़ने के लिए क्षेत्र
selfdocumenting है, हालांकि क्षेत्र में से एक फायदा है:
यह सार्वजनिक इंटरफ़ेस है कि यह वास्तव अपरिवर्तनीय है (छोड़कर प्रतिबिंब) पर एक नज़र में स्पष्ट करता है। जबकि किसी संपत्ति के मामले में आप केवल देख सकते हैं कि आप इसे बदल नहीं सकते हैं, इसलिए आपको दस्तावेज़ या कार्यान्वयन का संदर्भ लेना होगा।

लेकिन ईमानदार होने के लिए मैं आलसी हूं क्योंकि मैं अक्सर आवेदन कोड में पहले व्यक्ति का उपयोग करता हूं। पुस्तकालयों में मैं आम तौर पर अधिक गहन हूं और सम्मेलन का पालन करता हूं।

सी # 6.0 केवल पढ़ने के लिए स्वत: गुण

public object MyProperty { get; } 

कहते हैं तो जब आप पुराने compilers आपको लगता है कि बस के रूप में एक केवल पढ़ने के लिए क्षेत्र के रूप में संक्षिप्त है कोड के साथ वास्तव में केवल पढ़ने के लिए संपत्ति हो सकती है समर्थन करने के लिए की जरूरत नहीं है।

49

दूसरा तरीका पसंदीदा विकल्प है।

private readonly int MyVal = 5; 

public int MyProp { get { return MyVal;} } 

यह सुनिश्चित होगा कि MyVal केवल (यह भी एक निर्माता में सेट किया जा सकता) प्रारंभ में सौंपा जा सकता है।

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

+0

धन्यवाद। पहला विकल्प भी वही सुनिश्चित करता है। आपको क्या लगता है कि यह एक पसंदीदा विकल्प क्यों है? – akonsu

+0

क्या कोई कारण है कि हमें 'सार्वजनिक int MyProp {get; निजी सेट; } '? मुझे पता है कि यह वास्तव में पढ़ा नहीं है, लेकिन यह बहुत सुंदर है। –

+3

@ माइक होफर - चूंकि int को _readonly_ के रूप में घोषित किया गया है, इसलिए आप इसे किसी कन्स्ट्रक्टर के बाहर नहीं बदल सकते हैं। – Oded

4

दूसरी विधि को encapsulation की वजह से प्राथमिकता दी जाती है। आप निश्चित रूप से पठनीय क्षेत्र सार्वजनिक हो सकते हैं, लेकिन यह सी # मुहावरे के खिलाफ चला जाता है जिसमें आपके पास डेटा एक्सेस होता है और गुणों के माध्यम से नहीं होता है।

इसके पीछे तर्क यह है कि संपत्ति सार्वजनिक इंटरफ़ेस को परिभाषित करती है और यदि उस संपत्ति का समर्थन कार्यान्वयन बदलता है, तो आप शेष कोड को तोड़ने को समाप्त नहीं करते हैं क्योंकि कार्यान्वयन एक इंटरफ़ेस के पीछे छिपा हुआ है।

5

मैं मानता हूं कि दूसरा तरीका बेहतर है। उस वरीयता का एकमात्र असली कारण सामान्य प्राथमिकता है कि .NET कक्षाओं में सार्वजनिक फ़ील्ड नहीं हैं। हालांकि, अगर वह क्षेत्र पढ़ा जाता है, तो मैं नहीं देख सकता कि अन्य गुणों के साथ स्थिरता की कमी के अलावा कोई वास्तविक आपत्ति कैसे होगी। एक पठनीय क्षेत्र और केवल एकमात्र संपत्ति के बीच वास्तविक अंतर यह है कि पाठक क्षेत्र एक गारंटी प्रदान करता है कि इसका मूल्य वस्तु के जीवन में नहीं बदलेगा और केवल एकमात्र संपत्ति नहीं है।

+0

यह एक अच्छा स्पष्टीकरण है। धन्यवाद। – akonsu

8

आप ऐसा कर सकते हैं:

public int Property { get { ... } private set { ... } } 
+4

हां, आप कर सकते हैं, लेकिन इस तकनीक के साथ आप केवल गारंटी देते हैं कि संपत्ति कक्षा के उपभोक्ताओं द्वारा संशोधित नहीं की जा सकती है, न कि यह वस्तु के जीवनकाल के लिए स्थिर रहेगी। –

35
सी # 6 की शुरूआत के साथ

(वी.एस. 2015 में), अब आप get -only स्वत: गुण है, जो में निहित समर्थन क्षेत्र readonly (यानी मूल्यों निर्माता में सौंपा जा सकता है लेकिन और कहीं नहीं) है हो सकता है:

public string Name { get; } 

public Customer(string name) // Constructor 
{ 
    Name = name; 
} 

private void SomeFunction() 
{ 
    Name = "Something Else"; // Compile-time error 
} 

और तुम अब भी गुण (के साथ या बिना एक सेटर) इनलाइन आरंभ कर सकते हैं:

public string Name { get; } = "Boris"; 

वापस सवाल की चर्चा करते हुए यह आप विकल्प 2 के फायदे देता है (सार्वजनिक सदस्य एक संपत्ति नहीं है, एक क्षेत्र) ब्रेवटी के साथ विकल्प 1.

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

+0

हालांकि, नए सिंटैक्स पर अच्छी जानकारी, आप एक निजी सेटर को प्रतिबिंबित और सक्रिय कर सकते हैं और/या बैकिंग फ़ील्ड में एक मान लोड कर सकते हैं (एक्सेस मॉडिफायर्स के बावजूद।) एक निजी सेटर और एक सेटर की कमी के बीच अंतर करना भी संभव है प्रतिबिंब का उपयोग कर रन-टाइम। –

+1

@ शुन: अच्छा बिंदु - प्रतिबिंब के साथ आप * बहुत सारी चीजें कर सकते हैं! संभवतः मूल प्रोग्रामर या यहां तक ​​कि भाषा डिजाइनरों के इरादे के खिलाफ कई संभावनाएं हैं, लेकिन क्या आप कह रहे हैं कि 'रीडोनली' फ़ील्ड प्रतिबिंब का उपयोग करके बदला जा सकता है (मुझे जवाब नहीं पता, लेकिन यह समस्याग्रस्त लगता है)? –

+2

मैं यह नहीं कह रहा था कि विशेष रूप से, नहीं, लेकिन जवाब है: हाँ .. आप कर सकते हैं। https://gist.github.com/wilson0x4d/a053c0fd57892d357b2c यदि आपको लगता है कि यह समस्याग्रस्त है, तो बस जब तक आप सीखें कि ग्रह पर हर ऑपरेटिंग सिस्टम में एक तंत्र है जहां एक प्रक्रिया किसी भी अन्य प्रक्रिया की स्मृति को पढ़/लिख सकती है पर्याप्त निष्पादन विशेषाधिकार, जो है।) यही कारण है कि कोई सॉफ़्टवेयर-आधारित सिस्टम कभी भी सुरक्षित नहीं हो सकता है, लेकिन, मैं digress, यह मूल प्रश्न के साथ बहुत कुछ नहीं है :) भले ही यह दिलचस्प है! –