2010-05-10 11 views
34

Design Guidelines for Developing Class Libraries में, माइक्रोसॉफ्ट का कहना है:माइक्रोसॉफ्ट म्यूटेबल मूल्यों के साथ पठनीय क्षेत्रों के खिलाफ क्यों सलाह देता है?

Do not assign instances of mutable types to read-only fields.

The objects created using a mutable type can be modified after they are created. For example, arrays and most collections are mutable types while Int32, Uri, and String are immutable types. For fields that hold a mutable reference type, the read-only modifier prevents the field value from being overwritten but does not protect the mutable type from modification.

यह केवल समझा क्यों यह केवल पढ़ने के लिए उपयोग करने के लिए बुरा है बिना केवल पढ़ने के व्यवहार restates। निहितार्थ यह प्रतीत होता है कि बहुत से लोग समझ में नहीं आता कि "केवल पढ़ने" क्या करता है और गलत तरीके से केवल पढ़ने वाले क्षेत्रों को गहराई से अपरिवर्तनीय होने की उम्मीद करेगा। असल में यह "पाठक" का उपयोग करने के लिए गहरी अपरिवर्तनीयता को इंगित करने वाले कोड दस्तावेज के रूप में उपयोग करने की सलाह देता है - इस तथ्य के बावजूद कि कंपाइलर को इसे लागू करने का कोई तरीका नहीं है - और इसके सामान्य कार्य के लिए इसका उपयोग अस्वीकार करता है: यह सुनिश्चित करने के लिए कि फ़ील्ड का मान बदल नहीं जाता है वस्तु का निर्माण किया गया है।

मैं उपयोग करने के लिए "केवल पढ़ने के लिए" अपनी सामान्य संकलक द्वारा समझे गए अर्थ के अलावा कुछ इंगित करने के लिए इस सिफारिश के साथ असहज महसूस। मुझे लगता है कि यह लोगों को "पठनीय" के अर्थ को गलत समझने के लिए प्रोत्साहित करता है, और इसके अलावा यह उम्मीद करने के लिए कि कोड के लेखक का इरादा नहीं हो सकता है। मुझे लगता है कि यह उन जगहों पर इसका उपयोग रोकता है जो उपयोगी हो सकते हैं - उदा। यह दिखाने के लिए कि दो म्यूटेबल ऑब्जेक्ट्स के बीच कुछ रिश्ते उन वस्तुओं में से एक के जीवनकाल के लिए अपरिवर्तित बनी हुई है। यह मानने की धारणा है कि पाठकों को "पठनीय" के अर्थ को समझ में नहीं आता है, यह भी माइक्रोसॉफ्ट की अन्य सलाह के विपरीत है, जैसे कि FxCop के "Do not initialize unnecessarily" नियम, जो आपके कोड के पाठकों को भाषा में विशेषज्ञ मानते हैं और उन्हें पता होना चाहिए (उदाहरण के लिए) बूल फ़ील्ड्स को स्वचालित रूप से झूठी शुरू कर दिया जाता है, और आपको अनावश्यकता प्रदान करने से रोकता है जो दिखाता है "हां, यह जानबूझकर झूठ पर सेट हो गया है; मैं इसे शुरू करना न भूल गया"।

तो, पहली और महत्वपूर्ण बात, क्यों माइक्रोसॉफ्ट परिवर्तनशील प्रकार के लिए संदर्भ के लिए केवल पढ़ने के उपयोग की सलाह नहीं देते हैं? मुझे यह भी जानने में दिलचस्पी होगी:

  • क्या आप अपने सभी कोड में इस डिज़ाइन दिशानिर्देश का पालन करते हैं?
  • जब आप कोड लिखने वाले कोड में "readonly" देखते हैं तो आप क्या उम्मीद करते हैं?
+2

100% सहमत हैं। विशिष्ट माइक्रोसॉफ्ट दिशानिर्देश। \ * फ्लश \ * –

+0

मैं यह नहीं कह सकता कि मैं पूर्वाग्रह से मुक्त हूं। ;) मुझे लगा कि एंथनी का जवाब, सटीक होने पर, कुछ भी नहीं कहा गया था जो दिशानिर्देश में पहले से ही नहीं बताया गया था: म्यूटेबल ऑब्जेक्ट्स के रीडोनली संदर्भ खराब हैं ... क्योंकि वस्तु उत्परिवर्तनीय है। दूसरी तरफ, आपके उत्तर ने कम से कम विस्तृत किया कि आप म्यूटेबल ऑब्जेक्ट्स के रीडोनली संदर्भ क्यों लेना चाहते हैं। अब जब मैं इसे देखता हूं, शायद स्टैक्स का जवाब है - सख्ती से बोलना - मूल रूप से पूछे गए प्रश्न का सबसे सटीक उत्तर। – Weeble

उत्तर

18

मैं तुम्हें पूरी तरह से से सहमत , और मैं कभी कभी ऐसा परिवर्तनशील संदर्भ प्रकार के लिए मेरी कोड में readonly का उपयोग करें।

एक उदाहरण के रूप: मैं कुछ private या protected सदस्य हो सकता है - कहते हैं, एक List<T> - जो मैं अपने सभी परिवर्तनशील महिमा में एक वर्ग के तरीकों के भीतर का उपयोग करें (Add, Remove, आदि कह कर बुलाया)। मैं बस यह सुनिश्चित करने के लिए एक सुरक्षा उपाय रखना चाहता हूं कि, कोई फर्क नहीं पड़ता कि मैं हमेशा एक ही ऑब्जेक्ट से निपट रहा हूं। यह मुझे और अन्य डेवलपर्स दोनों को बेवकूफ करने से बचाता है: अर्थात्, सदस्य को एक नई वस्तु को असाइन करना।

मेरे लिए, यह एक निजी set विधि के साथ संपत्ति का उपयोग करने के लिए अक्सर एक बेहतर विकल्प होता है। क्यूं कर? क्योंकि readonly का अर्थ है बेस क्लास द्वारा तत्कालता के बाद मूल्य बदला नहीं जा सकता है।

दूसरे शब्दों में, अगर मैं इस किया था:

protected List<T> InternalList { get; private set; } 

तो मैं अभी भी अपने आधार वर्ग में कोड में किसी भी मनमाने ढंग से बिंदु पर InternalList = new List<T>(); सेट कर सकते हैं। (यह, मेरी ओर से एक बहुत ही मूर्ख त्रुटि की आवश्यकता होगी हाँ, लेकिन यह अभी भी संभव हो जाएगा।)

दूसरी ओर, इस:

protected readonly List<T> _internalList; 

बनाता है यह निश्चय स्पष्ट कि _internalListकर सकते हैं केवल एक विशेष वस्तु का संदर्भ लें (एक जिसे _internalList कन्स्ट्रक्टर में सेट किया गया है)।

तो मैं आपकी तरफ हूं। यह विचार कि किसी को एक म्यूटेबल संदर्भ प्रकार पर readonly का उपयोग करने से बचना चाहिए, मुझे व्यक्तिगत रूप से निराशाजनक है, क्योंकि यह मूल रूप से readonly कीवर्ड की गलतफहमी को पूर्ववत करता है।

+0

+1, पूरी तरह से सहमत, निजी + readonly = कोड में कम चिंताएं। –

+0

मैं संदर्भ प्रकारों पर निजी रूप से पढ़ता हूं। यह सुनिश्चित करने के लिए एकदम सही है कि मैं कक्षा में अपनी निर्भरताओं को कभी नहीं छूता। मैं कभी भी एक पठनीय निजी क्षेत्र को अपरिवर्तनीय होने की उम्मीद नहीं करता हूं। मैंने कहा कि मैं एमएस guidline या तो समझ में नहीं आता है। मुझे लगता है कि पाठों के अनजान डेवलपर्स की सुरक्षा के बजाय सुविधा का उपयोग करना बेहतर है, जिन्हें उन्हें निश्चित रूप से सीखना चाहिए। – Console

25

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

Foo foo = new Foo(); 
foo.Bar = new Baz(); 

लेकिन मैं

foo.Bar.Name = "Blah"; 

कह के साथ भाग प्राप्त कर सकते हैं वस्तु समर्थन बार वास्तव में, है, परिवर्तनशील। माइक्रोसॉफ्ट बस उस सूक्ष्म, counterintuitive व्यवहार के खिलाफ सिफारिश कर रहा है यह सुझाव देकर कि पाठक क्षेत्रों को अपरिवर्तनीय वस्तुओं द्वारा समर्थित किया जा सकता है।

+1

आप कहते हैं कि प्राकृतिक लगता है, लेकिन यह मेरे लिए ऐसा प्रतीत नहीं होता है। यह * वांछनीय * प्रतीत हो सकता है कि गहरी अपरिवर्तनीयता निर्दिष्ट करने के कुछ साधन हैं, लेकिन ऐसा लगता है कि यह * प्राकृतिक * नहीं है जो इसे पढ़ा जाना चाहिए, और यहां तक ​​कि यह स्पष्ट रूप से निष्कर्ष तक नहीं पहुंचाता है कि हमें व्यवहार करना चाहिए * जैसा कि * जब यह नहीं है तो रीडोनली का वास्तविक अर्थ। – Weeble

2

माइक्रोसॉफ्ट की कुछ ऐसी अनोखी सलाहएं हैं। दूसरा जो तुरंत दिमाग में झुकता है वह सार्वजनिक सदस्यों में सामान्य प्रकारों को घोंसला नहीं करना है, जैसे List<List<int>>। मैं इन संरचनाओं से बचने की कोशिश करता हूं जहां आसानी से संभव है, लेकिन जब मुझे लगता है कि उपयोग उचित है तो नौसिखिया-अनुकूल सलाह को अनदेखा करें।

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

+0

आप एक अच्छा मुद्दा उठाते हैं - क्या डिज़ाइन दिशानिर्देश केवल गैर-निजी सदस्यों पर लागू होते हैं? दिशानिर्देश पहले से ही सार्वजनिक या संरक्षित क्षेत्रों का उपयोग नहीं करते हैं। मुझे लगता है कि वे पुस्तकालय के सार्वजनिक एपीआई पर केंद्रित हैं, जिस पर निजी क्षेत्रों में स्पष्ट रूप से कोई असर नहीं है। मुझे निश्चित रूप से * सार्वजनिक * रीडोनली म्यूटेबल फ़ील्ड रखने की दबदबा की आवश्यकता महसूस नहीं होती है, क्योंकि मुझे शायद ही कभी सार्वजनिक क्षेत्र की आवश्यकता महसूस हो रही है। – Weeble

1

अंत में वे केवल दिशानिर्देश हैं।मुझे इस तथ्य के बारे में पता है कि माइक्रोसॉफ्ट के लोग अक्सर सभी दिशानिर्देशों का पालन नहीं करते हैं।

7

DO NOT assign instances of mutable types to readonly fields.

मैं फ्रेमवर्क डिजाइन दिशानिर्देश पुस्तक (पृष्ठों 161-162) में शीघ्रता से अवलोकन किया था, और यह मूल रूप से कहा गया है कि आपको पहले से अपने आप को देखा है। वहाँ जो डफी द्वारा एक अतिरिक्त टिप्पणी है कि दिशानिर्देश के अस्तित्व-'घ बताते है:

What this guideline is trying to protect you from is believing you've exposed a deeply immutable object graph when in fact it is shallow, and then writing code that assumes the whole graph is immutable.
— Joe Duffy

मैं व्यक्तिगत रूप से लगता है कि कीवर्ड readonly बुरी तरह से नामित किया गया था। तथ्य यह है कि यह केवल संदर्भ के कॉन्स्टेस को निर्दिष्ट करता है, न कि संदर्भित वस्तु के कॉन्स्टेस की, आसानी से भ्रामक स्थितियों को बनाता है।

मुझे लगता है कि अगर readonly संदर्भित संदर्भित वस्तुओं को अपरिवर्तनीय, भी, न केवल संदर्भित किया गया है, क्योंकि कीवर्ड का तात्पर्य है।

इस दुर्भाग्यपूर्ण स्थिति को हल करने के लिए, दिशानिर्देश बनाया गया था।जबकि मुझे लगता है कि इसकी सलाह मानव बिंदु दृश्य से अच्छी है (यह हमेशा स्पष्ट नहीं होता है कि कौन से प्रकार म्यूटेबल हैं और जो उनकी परिभाषा को देखे बिना नहीं हैं, और शब्द गहरी अपरिवर्तनीयता का सुझाव देता है), मैं कभी-कभी यह चाहता हूं कि, कब यह कॉन्स्टेस घोषित करने की बात आती है, सी # सी ++ द्वारा प्रदान की गई स्वतंत्रता की पेशकश करेगा, जहां आप पॉइंटर पर, या पॉइंट-टू-ऑब्जेक्ट पर या दोनों या कुछ भी नहीं पर const परिभाषित कर सकते हैं।

+1

जबकि मैं आपके बिंदु को समझता हूं, एक चीज जो मैं निश्चित रूप से * की इच्छा नहीं करता वह भयानक सी ++ - शैली 'const' है। –

+0

_ @ जेएस बैंग्स: _ बेशक यह व्यक्तिगत वरीयताओं पर आता है। सी का प्रकार घोषणा वाक्यविन्यास वास्तव में है ... अच्छा, "विशेष", लेकिन बहुत लचीलापन प्रदान करता है। सी का 'कॉन्स' शायद सी #/नेट की टाइप सिस्टम की सापेक्ष सादगी में अच्छी तरह से फिट नहीं होगा ... फिर भी मुझे कभी-कभी इसे याद आती है। 'कॉन्स' कई लोगों के विचार से अधिक शक्तिशाली उपकरण है। – stakx

+0

उपरोक्त, लेकिन मैं एक बिंदु पर असहमत हूं कि केवल संदर्भित वस्तुओं को अपरिवर्तनीय बनाना चाहिए। मैं नहीं देख सकता कि सिस्टम के बिना काम करना सी ++ के मुकाबले कहीं अधिक जटिल है: जब आप किसी ऑब्जेक्ट को रीडोनली संदर्भ के माध्यम से एक्सेस करते हैं, तो क्या इससे इसकी सभी संपत्तियां और फ़ील्ड रीडोनली संदर्भ लौटाती हैं? इसके विधि वापसी मूल्यों के बारे में क्या? क्या आपको विधियों को स्पष्ट रूप से घोषित/स्पष्ट रूप से घोषित करने का कोई तरीका चाहिए? जब ऑब्जेक्ट किसी अन्य असेंबली में घोषित प्रकार का होता है तो यह सब कैसे काम करता है? – Weeble

1

वाक्य रचना आप के लिए C++/CLI भाषा के द्वारा समर्थित है देख रहे हैं:

const Example^ const obj; 

पहले स्थिरांक संदर्भित वस्तु अपरिवर्तनीय बनाता है, 2 संदर्भ अपरिवर्तनीय बना देता है। उत्तरार्द्ध सी # में केवल पढ़ने योग्य कीवर्ड के बराबर है। से बचने के लिए यह एक संकलन त्रुटि उत्पन्न प्रयास:

Test^ t = gcnew Test(); 
t->obj = gcnew Example(); // Error C3892 
t->obj->field = 42;   // Error C3892 
Example^ another = t->obj; // Error C2440 
another->field = 42; 

हालांकि यह धूम्रपान और दर्पण है। अपरिवर्तनीयता को संकलक द्वारा सत्यापित किया जाता है, सीएलआर द्वारा नहीं। एक और प्रबंधित भाषा दोनों को संशोधित कर सकती है। समस्या की जड़ कौन सा है, सीएलआर के लिए इसका समर्थन नहीं है।

संबंधित मुद्दे