मैं एक अपरिवर्तनीय कक्षा कैसे बनाऊं?


113

मैं एक अपरिवर्तनीय वर्ग बनाने पर काम कर रहा हूं।
मैंने सभी गुणों को केवल-पढ़ने के लिए चिह्नित किया है।

मेरे पास कक्षा में वस्तुओं की एक सूची है।
यद्यपि यदि संपत्ति केवल पढ़ने के लिए है तो सूची को संशोधित किया जा सकता है।

सूची के IEnumerable को उजागर करना अपरिवर्तनीय बनाता है।
मैं जानना चाहता था कि कक्षा को अपरिवर्तनीय बनाने के लिए बुनियादी नियमों का क्या पालन करना है?


2
मैं दृढ़ता से अनुशंसा करता हूं कि आप एरिक लिपर्ट के ब्लॉग श्रृंखला को अपरिवर्तनीयता पर पढ़ते हैं , विशेष रूप से "अपरिवर्तनीयता" पर प्रविष्टि । आपकी टिप्पणी कि "सूची के IEnumerable को उजागर करना अपरिवर्तनीय बनाता है" मुझे कुछ अजीब लगता है। आपका इससे क्या मतलब है?
जॉन स्कीट

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

1
एरिक लिपर्ट की ब्लॉग श्रृंखला में जॉन स्कीट के लिंक तब टूट गए जब MSDN ने इन ब्लॉगों को संग्रहीत किया। कृपया "अपरिवर्तनीयता के प्रकार" देखें । शेष श्रृंखला दिसंबर 2007 + जनवरी 2008 के तहत बाएं हाथ के पैनल में लगती है।
जॉन डोए

कृपया कैसे लोगों को आम तौर पर मामले को भ्रमित पर एरिक Lippert के ब्लॉग श्रृंखला को देखने के atomicity, volatilityऔर immutability: भाग एक , भाग दो , और भाग तीन । ये उनके निजी ब्लॉग से हैं और मेरा मानना ​​है कि उनके MSDN पोस्ट्स की तुलना में अधिक नौसिखिया-मित्र हैं।
जॉन डोए

जवाबों:


121

मुझे लगता है कि आप सही रास्ते पर हैं -

  • कक्षा में इंजेक्ट की गई सभी जानकारी को कंस्ट्रक्टर में आपूर्ति की जानी चाहिए
  • सभी गुण केवल गेटर्स होने चाहिए
  • यदि संग्रह (या एरे) को कंस्ट्रक्टर में पारित किया जाता है, तो इसे बाद में संशोधित करने से कॉलर को रखने के लिए कॉपी किया जाना चाहिए
  • यदि आप अपना संग्रह वापस करने जा रहे हैं, तो या तो एक प्रति या केवल पढ़ने के लिए एक संस्करण लौटाएँ (उदाहरण के लिए, ArrayList.ReadOnly या इसी तरह का उपयोग करके - आप इसे पिछले बिंदु के साथ जोड़ सकते हैं और पढ़े जाने के लिए केवल पढ़ी जाने वाली प्रतिलिपि संग्रहीत कर सकते हैं कॉलर इसे एक्सेस करते हैं), एक एन्यूमरेटर लौटाते हैं, या कुछ अन्य विधि / संपत्ति का उपयोग करते हैं जो संग्रह में केवल पढ़ने की अनुमति देता है
  • ध्यान रखें कि आपके पास अभी भी एक उत्परिवर्तित वर्ग की उपस्थिति हो सकती है यदि आपका कोई सदस्य उत्परिवर्तित है - यदि यह मामला है, तो आपको उस प्रतिलिपि को हटा देना चाहिए जो आप किसी भी राज्य को बनाए रखना चाहते हैं और जब तक आप उन्हें कॉपी नहीं करते, तब तक आप सभी उत्परिवर्तित वस्तुओं को वापस करने से बचेंगे। कॉल करने वाले को वापस देने से पहले - एक अन्य विकल्प केवल उत्परिवर्तनीय वस्तु के अपरिवर्तनीय "वर्गों" को वापस करना है - इस बिंदु का विस्तार करने के लिए मुझे प्रोत्साहित करने के लिए @Brian रासमुसेन का धन्यवाद।

क्या मुझे एक रैपर लुक अप प्रॉपर्टी लिखनी चाहिए, जो आपको केवल लुक अप करने की सुविधा देता है? और उत्तर के लिए धन्यवाद।
बिश्वनाथ

5
निर्माणकर्ता के तर्क के रूप में पारित किसी भी परिवर्तनशील संदर्भ प्रकार को कॉपी किया जाना चाहिए। अन्यथा कॉल करने वाला अभी भी राज्य का संदर्भ रखेगा।
ब्रायन रासमुसेन

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

@ ब्लेयर - अगर मेरे पास कक्षा में शब्दकोष है जिसे मैं सिर्फ लुक अप के लिए उपयोग करना चाहता हूं। क्या केवल पढ़ने योग्य संपत्ति है जो एक नज़र आती है, ठीक होनी चाहिए?
बिस्वनाथ

@ बिश्वनाथ - हाँ, इस चेतावनी के साथ कि यदि शब्दकोश में मान परस्पर भिन्न हैं, तो लौटने से पहले आपको उनकी रक्षा करने की आवश्यकता होगी, यदि आप उन्हें उत्परिवर्तित नहीं करना चाहते हैं
ब्लेयर कॉनरैड

18

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

आप निम्नानुसार एक सूची सूची संपत्ति बना सकते हैं:

public class MyClass
{
    public MyClass(..., IList<MyType> items)
    {
        ...
        _myReadOnlyList = new List<MyType>(items).AsReadOnly();
    }

    public IList<MyType> MyReadOnlyList
    {
        get { return _myReadOnlyList; }
    }
    private IList<MyType> _myReadOnlyList

}

1
मुझे लगता है कि ImmutableList बेहतर होगा।
केविन वोंग


मुझे यकीन नहीं है कि ImmutableList इस उपयोग के मामले के लिए एक अच्छा फिट है basic rules to make a class (that contains a list) immutable:। ImmutableList शब्दार्थ सूची की एक प्रति में आइटम जोड़ते समय अधिक कुशल मेमोरी उपयोग को सक्षम करता है, लेकिन यह मुझे एक अधिक विशिष्ट उपयोग मामला लगता है।
जो

11

यह भी ध्यान रखें कि:

public readonly object[] MyObjects;

भले ही वह आसानी से पढ़े गए कीवर्ड से चिह्नित न हो। इंडेक्स एक्सेसर द्वारा आप अभी भी अलग-अलग एरे संदर्भ / मान बदल सकते हैं।


5

ReadOnlyCollectionकक्षा का उपयोग करें । में स्थित हैSystem.Collections.ObjectModel नामस्थान ।

आपकी सूची (या कंस्ट्रक्टर) में वापस आने वाली किसी भी चीज़ पर, सूची को केवल-पढ़ने के लिए संग्रह के रूप में सेट करें।

using System.Collections.ObjectModel;

...

public MyClass(..., List<ListItemType> theList, ...)
{
    ...
    this.myListItemCollection= theList.AsReadOnly();
    ...
}

public ReadOnlyCollection<ListItemType> ListItems
{
     get { return this.myListItemCollection; }
}

1

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


1

ReadOnlyCollection का उपयोग करके क्लाइंट को इसे संशोधित करने से प्रतिबंधित किया जाएगा।

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