क्या .NET में केवल पढ़ने के लिए सामान्य शब्दकोष उपलब्ध है?


186

मैं अपने केवल पढ़ी गई संपत्ति में एक शब्दकोश का संदर्भ दे रहा हूं। मैं उपभोक्ताओं को अपना डेटा बदलने से कैसे रोकूं? यदि यह IListमैं होता तो बस इसे वापस कर सकता था AsReadOnly। क्या ऐसा ही कुछ मैं एक शब्दकोश के साथ कर सकता हूं?

Private _mydictionary As Dictionary(Of String, String)
Public ReadOnly Property MyDictionary() As Dictionary(Of String, String)
    Get
        Return _mydictionary
    End Get
End Property

4
इसे करने का कोई न कोई तरीका होना चाहिए, वरना आईडीआरआईडी पर एक IsReadOnly प्रॉपर्टी नहीं होती ... ( msdn.microsoft.com/en-us/library/bb338949.aspx )
पॉवरलॉर्ड

2
अपरिवर्तनीयता के कई वैचारिक लाभों को बिना रनटाइम के प्राप्त किया जा सकता है। यदि यह एक निजी परियोजना है, तो एक अनुशासित, अनौपचारिक विधि पर विचार करें। यदि आपको किसी उपभोक्ता को डेटा प्रदान करना है, तो आपको गहरी प्रतियों पर गंभीरता से विचार करना चाहिए। जब आप समझते हैं कि एक अपरिवर्तनीय संग्रह के लिए 1) संग्रह के संदर्भ में 1) अपरिवर्तनीय संदर्भ की आवश्यकता होती है) तो अनुक्रम को स्वयं 3 और 3 को रोकना) संग्रह की वस्तुओं पर गुणों को संशोधित करने से रोकता है, और इनमें से कुछ का प्रतिबिंब द्वारा उल्लंघन किया जा सकता है, रनटाइम प्रवर्तन है अप्रायौगिक।
Sprague

27
.NET 4.5 के बाद से, एक System.Collections.ObjectModel.ReadOnlyDictionary ^ _ ^
Smartkid

2
अब भी Microsoft अपरिवर्तनीय संग्रह NuGet msdn.microsoft.com/en-us/library/dn385366%28v=vs.110%29.aspx के
वोट कॉफ़ी

जवाबों:


156

यहां एक सरल कार्यान्वयन है जो एक शब्दकोश लपेटता है:

public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    private readonly IDictionary<TKey, TValue> _dictionary;

    public ReadOnlyDictionary()
    {
        _dictionary = new Dictionary<TKey, TValue>();
    }

    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
    {
        _dictionary = dictionary;
    }

    #region IDictionary<TKey,TValue> Members

    void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
    {
        throw ReadOnlyException();
    }

    public bool ContainsKey(TKey key)
    {
        return _dictionary.ContainsKey(key);
    }

    public ICollection<TKey> Keys
    {
        get { return _dictionary.Keys; }
    }

    bool IDictionary<TKey, TValue>.Remove(TKey key)
    {
        throw ReadOnlyException();
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        return _dictionary.TryGetValue(key, out value);
    }

    public ICollection<TValue> Values
    {
        get { return _dictionary.Values; }
    }

    public TValue this[TKey key]
    {
        get
        {
            return _dictionary[key];
        }
    }

    TValue IDictionary<TKey, TValue>.this[TKey key]
    {
        get
        {
            return this[key];
        }
        set
        {
            throw ReadOnlyException();
        }
    }

    #endregion

    #region ICollection<KeyValuePair<TKey,TValue>> Members

    void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
    {
        throw ReadOnlyException();
    }

    void ICollection<KeyValuePair<TKey, TValue>>.Clear()
    {
        throw ReadOnlyException();
    }

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        return _dictionary.Contains(item);
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        _dictionary.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return _dictionary.Count; }
    }

    public bool IsReadOnly
    {
        get { return true; }
    }

    bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
    {
        throw ReadOnlyException();
    }

    #endregion

    #region IEnumerable<KeyValuePair<TKey,TValue>> Members

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion

    private static Exception ReadOnlyException()
    {
        return new NotSupportedException("This dictionary is read-only");
    }
}

11
+1 पूर्ण कोड पोस्ट करने के लिए और न केवल एक लिंक के लिए, लेकिन मैं उत्सुक हूं, ReadOnlyDictionary में एक खाली निर्माणकर्ता का क्या मतलब है? :-)
सैमुअल नेफ

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

25
@askheaves: अच्छा अवलोकन, लेकिन वास्तव में यह केवल पढ़ने के प्रकारों में मूल संदर्भ का उपयोग करने के लिए काफी उपयोगी है - अपने निजी चर को मूल में रखें और इसे बाहरी उपभोक्ताओं के लिए संशोधित करें। उदाहरण के लिए, ReadOnlyObservableCollection या ReadOnlyCollection ऑब्जेक्ट जो इसमें बनाए गए हैं: थॉमस ने ऐसा कुछ प्रदान किया है जो नेट फ्रेमवर्क के लिए निहित समान काम करता है। धन्यवाद थॉमस! +1
मैट डेकेरे

13
@ user420667: जिस तरह से इसे लागू किया गया है, यह एक "केवल पढ़ने के लिए एक गैर-पढ़ने वाला शब्दकोश" का दृश्य है। कुछ अन्य कोड मूल शब्दकोश की सामग्री को बदल सकते हैं, और ये परिवर्तन केवल-केवल शब्दकोश में दिखाई देंगे। यह वांछित व्यवहार हो सकता है, या नहीं, इस पर निर्भर करता है कि आप क्या हासिल करना चाहते हैं ...
थॉमस लेवेस्क

6
@Thomas: यह .NET BCL में ReadOnlyCollection के समान है। यह संभवतः एक संभव परिवर्तनशील संग्रह पर केवल पढ़ने के लिए दृश्य है। केवल पढ़ने का मतलब अपरिवर्तनीय नहीं है और अपरिवर्तनीयता की उम्मीद नहीं की जानी चाहिए।
जेफ येट्स

229

.NET 4.5

.NET फ्रेमवर्क 4.5 बीसीएल परिचय ReadOnlyDictionary<TKey, TValue>( स्रोत )।

जैसा कि .NET फ्रेमवर्क 4.5 बीसीएल में AsReadOnlyशब्दकोशों के लिए शामिल नहीं है , आपको अपना खुद का लिखना होगा (यदि आप इसे चाहते हैं)। यह निम्नलिखित की तरह कुछ होगा, जिनमें से सादगी शायद यह उजागर करती है कि यह .NET 4.5 के लिए प्राथमिकता क्यों नहीं थी।

public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(
    this IDictionary<TKey, TValue> dictionary)
{
    return new ReadOnlyDictionary<TKey, TValue>(dictionary);
}

.NET 4.0 और नीचे

.NET 4.5 करने से पहले, वहाँ कोई .NET फ़्रेमवर्क वर्ग है कि एक लपेटता है Dictionary<TKey, TValue>की तरह ReadOnlyCollection एक लपेटता सूची । हालांकि, इसे बनाना मुश्किल नहीं है।

यहाँ एक उदाहरण है - यदि आप ReadOnlyDictionary के लिए Google हैं तो कई अन्य हैं ।


7
ऐसा नहीं लगता है कि उन्हें AsReadOnly()हमेशा की तरह एक विधि बनाने के लिए याद किया गया था Dictionary<,>, इसलिए मुझे आश्चर्य है कि कितने लोग अपने नए प्रकार की खोज करेंगे। यह ढेर अतिप्रवाह धागा मदद करेगा, यद्यपि।
जेपी स्टिग नीलसन

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

1
ध्यान दें कि यह केवल एक आवरण है; अंतर्निहित शब्दकोश में परिवर्तन (निर्माणकर्ता को दिया गया) अभी भी केवल-केवल शब्दकोश को म्यूट करेगा। यह भी देखें stackoverflow.com/questions/139592/…
TrueWill

1
@JeffYates यह देखते हुए कि यह कितना सरल है, यह लिखते हुए कि इसे लिखने में समय खर्च करना है या नहीं, यह तय करने में कम समय लगेगा। उसके कारण, मेरा दांव "वे भूल गए" पर है।
डैन बेहार्ड

जैसा कि TrueWill ने कहा है, अंतर्निहित शब्दकोश अभी भी म्यूट किया जा सकता है। यदि आप सही अपरिवर्तनीयता चाहते हैं, तो आप निर्माता को मूल शब्दकोश के एक क्लोन को पारित करने पर विचार कर सकते हैं (कुंजी और मूल्य प्रकार भी अपरिवर्तनीय हैं।)
user420667

19

हाल ही के BUILD सम्मेलन में यह घोषणा की गई थी कि .NET 4.5 के बाद से, इंटरफ़ेस System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>शामिल है। प्रमाण यहाँ है (मोनो) और यहाँ (Microsoft);)

यकीन है कि अगर ReadOnlyDictionaryयह भी शामिल नहीं है, लेकिन कम से कम इंटरफ़ेस के साथ यह अब एक कार्यान्वयन बनाने के लिए मुश्किल नहीं होना चाहिए जो एक आधिकारिक .NET नेटिक को उजागर करता है :)


5
ReadOnlyDictionary<TKey, TValue>(.Net 4.5) - msdn.microsoft.com/en-us/library/gg712875.aspx
myermian

18

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

public interface IReadOnlyDictionary<TKey, TValue> : IEnumerable
{
    bool ContainsKey(TKey key);
    ICollection<TKey> Keys { get; }
    ICollection<TValue> Values { get; }
    int Count { get; }
    bool TryGetValue(TKey key, out TValue value);
    TValue this[TKey key] { get; }
    bool Contains(KeyValuePair<TKey, TValue> item);
    void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex);
    IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator();
}

public class ReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
{
    readonly IDictionary<TKey, TValue> _dictionary;
    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
    {
        _dictionary = dictionary;
    }
    public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); }
    public ICollection<TKey> Keys { get { return _dictionary.Keys; } }
    public bool TryGetValue(TKey key, out TValue value) { return _dictionary.TryGetValue(key, out value); }
    public ICollection<TValue> Values { get { return _dictionary.Values; } }
    public TValue this[TKey key] { get { return _dictionary[key]; } }
    public bool Contains(KeyValuePair<TKey, TValue> item) { return _dictionary.Contains(item); }
    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { _dictionary.CopyTo(array, arrayIndex); }
    public int Count { get { return _dictionary.Count; } }
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return _dictionary.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return _dictionary.GetEnumerator(); }
}

4
IDictionaryअनुबंध का उल्लंघन नहीं करने के लिए +1 । मुझे लगता है कि IDictionaryविरासत के लिए OOP के नजरिए से यह अधिक सही है IReadOnlyDictionary
सैम

@ एसम सहमत, और अगर हम वापस जा सकते हैं तो मुझे लगता है कि यह IDictionary(वर्तमान के लिए IReadOnlyDictionary) और IMutableDictionary( वर्तमान के लिए ) सबसे अच्छा और सबसे सही होगा IDictionary
22

1
@MasterMastic यह एक विचित्र प्रस्ताव है। मैं किसी भी अन्य अंतर्निहित कक्षाओं को याद नहीं करता हूं जो रिवर्स धारणा पर निर्भर करता है कि एक अपरिवर्तनीय संग्रह वह है जो उपयोगकर्ता डिफ़ॉल्ट रूप से अपेक्षा करता है।
डैन बेहार्ड

11

IsReadOnly पर IDictionary<TKey,TValue>विरासत में मिला से है ICollection<T>( IDictionary<TKey,TValue>फैली हुई है ICollection<T>के रूप में ICollection<KeyValuePair<TKey,TValue>>)। यह किसी भी तरह से उपयोग या कार्यान्वित नहीं किया जाता है (और संबंधित ICollection<T>सदस्यों को स्पष्ट रूप से लागू करने के उपयोग के माध्यम से "छिपा हुआ" है )।

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

  1. एक कस्टम रीड को ही लागू करें IDictionary<TKey, TValue>और एक आंतरिक शब्दकोश में लपेटें / प्रतिनिधि करें जैसा कि सुझाया गया है
  2. ICollection<KeyValuePair<TKey, TValue>>केवल पढ़ने के लिए या IEnumerable<KeyValuePair<TKey, TValue>>मान के उपयोग के आधार पर एक सेट लौटाएं
  3. कॉपी कंस्ट्रक्टर का उपयोग करके शब्दकोश को क्लोन करें .ctor(IDictionary<TKey, TValue>)और एक कॉपी वापस करें - इस तरह से उपयोगकर्ता इसके साथ स्वतंत्र है जैसा कि वे कृपया करते हैं और यह स्रोत शब्दकोश की मेजबानी करने वाले ऑब्जेक्ट की स्थिति पर प्रभाव नहीं डालता है। ध्यान दें कि यदि आप जिस शब्दकोश का क्लोनिंग कर रहे हैं, उसमें संदर्भ प्रकार शामिल हैं (उदाहरण में दिखाए गए तार नहीं) तो आपको "मैन्युअल रूप से" प्रतिलिपि बनाने और संदर्भ प्रकारों को भी क्लोन करने की आवश्यकता होगी।

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


8

केवल पढ़ने के लिए कुछ हद तक शब्दकोश को प्रतिस्थापित किया जा सकता है Func<TKey, TValue>- मैं आमतौर पर एपीआई में इसका उपयोग करता हूं अगर मैं केवल लोगों को लुकअप करना चाहता हूं; यह सरल है, और विशेष रूप से, बैकएंड को बदलने के लिए यह सरल है जिसे आपको कभी भी करना चाहिए। हालाँकि, यह कुंजी की सूची प्रदान नहीं करता है; क्या यह मायने रखता है कि आप क्या कर रहे हैं पर निर्भर करता है।


4

नहीं, लेकिन अपना रोल करना आसान होगा। IDEDIA एक IsReadOnly संपत्ति को परिभाषित करता है। बस एक शब्दकोश लपेटें और उचित तरीकों से एक NotSupportedException फेंक दें।


3

बीसीएल में कोई भी उपलब्ध नहीं है। हालाँकि मैंने अपने BCL एक्स्ट्रा प्रोजेक्ट में एक ReadOnlyDictionary (जिसका नाम ImmutableMap है) प्रकाशित किया

एक पूरी तरह से अपरिवर्तनीय शब्दकोश होने के अलावा, यह एक प्रॉक्सी ऑब्जेक्ट का उत्पादन करने का समर्थन करता है जो IDfox को लागू करता है और किसी भी स्थान पर उपयोग किया जा सकता है जहां IDEDIA लिया जाता है। जब भी उत्परिवर्ती एपीआई में से एक को बुलाया जाता है तो यह एक अपवाद फेंक देगा

void Example() { 
  var map = ImmutableMap.Create<int,string>();
  map = map.Add(42,"foobar");
  IDictionary<int,string> dictionary = CollectionUtility.ToIDictionary(map);
}

9
आपका इम्मुटेबलेबल एक संतुलित पेड़ के रूप में लागू किया गया है। चूंकि, .NET में, लोग आमतौर पर हैशिंग के माध्यम से "शब्दकोश" को लागू करने की अपेक्षा करते हैं - और इसी जटिलता गुणों को प्रदर्शित करते हैं - आप चाहें तो ImmutableMap को "शब्दकोश" के रूप में प्रचारित करने के बारे में सावधान रह सकते हैं।
ग्लेन स्लेडेन 17

ऐसा प्रतीत होता है कि code.msdn.com साइटें दोषपूर्ण हैं। BCLextras अब यहाँ github.com/scottwis/tiny/tree/master/third-party/BclExtras
BozoJoe

1

आप एक ऐसा वर्ग बना सकते हैं जो केवल शब्दकोश के आंशिक कार्यान्वयन को लागू करता है, और सभी ऐड / रिमूव / सेट कार्यों को छुपाता है।

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

हालाँकि, चूंकि आपके शब्दकोश में संदर्भ प्रकारों को रखने की संभावना होती है, इसलिए उपयोगकर्ता को शब्दकोश द्वारा आयोजित कक्षाओं पर मूल्यों को स्थापित करने से रोकने का कोई तरीका नहीं है (जब तक कि उन कक्षाओं को केवल स्वयं नहीं पढ़ा जाता है)


1

मुझे नहीं लगता कि ऐसा करने का एक आसान तरीका है ... यदि आपका शब्दकोश एक कस्टम वर्ग का हिस्सा है, तो आप इसे एक अनुक्रमणिका के साथ प्राप्त कर सकते हैं:

public class MyClass
{
  private Dictionary<string, string> _myDictionary;

  public string this[string index]
  {
    get { return _myDictionary[index]; }
  }
}

मुझे पूरे शब्दकोश के साथ-साथ एक अनुक्रमणिका को भी उजागर करने में सक्षम होना चाहिए।
रोब सोबर्स

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

1

+1 महान नौकरी, थॉमस। मैंने रीडऑनलाइडर को एक कदम आगे बढ़ाया।

बहुत डेल के समाधान की तरह, मैं दूर करने के लिए चाहता था Add(), Clear(), Remove()IntelliSense से, आदि। लेकिन मैं चाहता था कि मेरी व्युत्पन्न वस्तुएं लागू हों IDictionary<TKey, TValue>

इसके अलावा, मैं निम्नलिखित कोड को तोड़ना चाहूंगा: (फिर, डेल का समाधान यह भी करता है)

ReadOnlyDictionary<int, int> test = new ReadOnlyDictionary<int,int>(new Dictionary<int, int> { { 1, 1} });
test.Add(2, 1);  //CS1061

ऐड () लाइन परिणाम में:

error CS1061: 'System.Collections.Generic.ReadOnlyDictionary<int,int>' does not contain a definition for 'Add' and no extension method 'Add' accepting a first argument 

कॉलर अभी भी इसे कास्ट कर सकता है IDictionary<TKey, TValue>, लेकिन NotSupportedExceptionयदि आप केवल गैर-पढ़ने वाले सदस्यों (थॉमस के समाधान से) का उपयोग करने का प्रयास करते हैं, तो इसे उठाया जाएगा।

वैसे भी, यहाँ किसी के लिए मेरा समाधान है कि यह भी चाहता था:

namespace System.Collections.Generic
{
    public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        const string READ_ONLY_ERROR_MESSAGE = "This dictionary is read-only";

        protected IDictionary<TKey, TValue> _Dictionary;

        public ReadOnlyDictionary()
        {
            _Dictionary = new Dictionary<TKey, TValue>();
        }

        public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
        {
            _Dictionary = dictionary;
        }

        public bool ContainsKey(TKey key)
        {
            return _Dictionary.ContainsKey(key);
        }

        public ICollection<TKey> Keys
        {
            get { return _Dictionary.Keys; }
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            return _Dictionary.TryGetValue(key, out value);
        }

        public ICollection<TValue> Values
        {
            get { return _Dictionary.Values; }
        }

        public TValue this[TKey key]
        {
            get { return _Dictionary[key]; }
            set { throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE); }
        }

        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return _Dictionary.Contains(item);
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            _Dictionary.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return _Dictionary.Count; }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return _Dictionary.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (_Dictionary as IEnumerable).GetEnumerator();
        }

        void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }

        bool IDictionary<TKey, TValue>.Remove(TKey key)
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }

        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }

        void ICollection<KeyValuePair<TKey, TValue>>.Clear()
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }

        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
        {
            throw new NotSupportedException(READ_ONLY_ERROR_MESSAGE);
        }
    }
}


0
public IEnumerable<KeyValuePair<string, string>> MyDictionary()
{
    foreach(KeyValuePair<string, string> item in _mydictionary)
        yield return item;
}

2
या आप कर सकते हैं:public IEnumerable<KeyValuePair<string, string>> MyDictionary() { return _mydictionary; }
पैट

0

यह एक बुरा समाधान है, नीचे देखें।

अभी भी .NET 4.0 या इससे पहले का उपयोग करने वालों के लिए, मेरे पास एक वर्ग है जो स्वीकृत उत्तर में एक की तरह काम करता है, लेकिन यह बहुत छोटा है। यह मौजूदा डिक्शनरी ऑब्जेक्ट का विस्तार करता है, कुछ सदस्यों को ओवरराइडिंग (वास्तव में छिपाना) जब उन्हें बुलाया जाता है तो उन्हें एक अपवाद फेंकने के लिए।

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

जरा देखो तो:

public class ReadOnlyException : Exception
{
}

public class ReadOnlyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
        : base(dictionary) { }

    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
        : base(dictionary, comparer) { }

    //The following four constructors don't make sense for a read-only dictionary

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public ReadOnlyDictionary() { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public ReadOnlyDictionary(IEqualityComparer<TKey> comparer) { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public ReadOnlyDictionary(int capacity) { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public ReadOnlyDictionary(int capacity, IEqualityComparer<TKey> comparer) { throw new ReadOnlyException(); }


    //Use hiding to override the behavior of the following four members
    public new TValue this[TKey key]
    {
        get { return base[key]; }
        //The lack of a set accessor hides the Dictionary.this[] setter
    }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public new void Add(TKey key, TValue value) { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public new void Clear() { throw new ReadOnlyException(); }

    [Obsolete("Not Supported for ReadOnlyDictionaries", true)]
    public new bool Remove(TKey key) { throw new ReadOnlyException(); }
}

इस समाधान में यहाँ वर्णित @supercat द्वारा बताई गई समस्या है:

var dict = new Dictionary<int, string>
{
    { 1, "one" },
    { 2, "two" },
    { 3, "three" },
};

var rodict = new ReadOnlyDictionary<int, string>(dict);
var rwdict = rodict as Dictionary<int, string>;
rwdict.Add(4, "four");

foreach (var item in rodict)
{
    Console.WriteLine("{0}, {1}", item.Key, item.Value);
}

एक संकलन-समय त्रुटि देने की बजाय जैसे मुझे उम्मीद थी, या एक रनटाइम-अपवाद जैसे मुझे उम्मीद थी, यह कोड त्रुटि के बिना चलता है। यह चार नंबर प्रिंट करता है। यह मेरा ReadOnlyDictionary एक ReadWriteDictionary बनाता है।


उस दृष्टिकोण के साथ समस्या यह है कि इस तरह के ऑब्जेक्ट को एक ऐसी विधि को पारित किया जा सकता है जो Dictionary<TKey,TValue>किसी भी कंपाइलर शिकायत के बिना उम्मीद करता है , और सादे-शब्दकोश प्रकार के संदर्भ को कास्टिंग या coercing करना किसी भी सुरक्षा को हटा देगा।
सुपरकाट

@ सुपरकार, बकवास, आप सही कह रहे हैं। मुझे लगा कि मेरे पास एक अच्छा उपाय भी है।
user2023861

मुझे याद है कि Dictionaryएक Cloneविधि के साथ व्युत्पन्न करना जो कि जंजीर है MemberwiseClone। दुर्भाग्य से, जबकि यह संभव है कि बैकिंग स्टोर्स को क्लोन करके किसी शब्दकोश को कुशलता से क्लोन करना संभव हो, इस तथ्य के privateबजाय कि बैकिंग स्टोर का protectedमतलब यह है कि उन्हें क्लोन करने के लिए एक व्युत्पन्न वर्ग के लिए कोई रास्ता नहीं है; MemberwiseCloneबैकिंग स्टोर्स के क्लोनिंग के बिना उपयोग करने का मतलब होगा कि मूल शब्दकोश में किए गए बाद के संशोधन क्लोन को तोड़ देंगे, और क्लोन के लिए किए गए संशोधनों से मूल टूट जाएगा।
सुपरकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.