2012-11-27 43 views
14

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

तो मेरा सवाल यह है कि, मेरे आंतरिक शब्दकोश को आईआरएडऑनली डिक्शनरी में बदलने या इसे संभालने के किसी अन्य तरीके से बदलने का एक प्रभावी तरीका है? जिन विकल्पों के बारे में मैं सोच सकता हूं वे हैं:

  1. दो आंतरिक शब्दकोशों को पकड़ें और उन्हें सिंक में रखें।
  2. संपत्ति का उपयोग होने पर और सभी ऑब्जेक्ट्स को अंदर डालने पर एक नया शब्दकोश बनाएं।
  3. आईआरएड को केवल वापस पढ़ने के लिए नोट करें केवल आंतरिक रूप से इसका उपयोग करते समय।

1 दर्द की तरह लगता है, 2 अत्यधिक अक्षम लगता है। 3 इस समय सबसे अधिक आशाजनक की तरह लगता है, लेकिन अभी भी बदसूरत है। क्या मेरे पास अन्य विकल्प भी है?

public class ExposesReadOnly 
{ 
    private Dictionary<int, NotReadOnly> InternalDict { get; set; } 
    public IReadOnlyDictionary<int, IReadOnly> PublicList 
    { 
     get 
     { 
      // This doesn't work... 
      return this.InternalDict; 
     } 
    } 

    // This class can be modified internally, but I don't want 
    // to expose this functionality. 
    private class NotReadOnly : IReadOnly 
    { 
     public string Name { get; set; } 
    } 
} 

public interface IReadOnly 
{ 
    string Name { get; } 
} 

उत्तर

11

आप शब्दकोश के लिए अपने स्वयं के केवल पढ़ने के लिए आवरण, जैसे लिख सकते हैं:

public class ReadOnlyDictionaryWrapper<TKey, TValue, TReadOnlyValue> : IReadOnlyDictionary<TKey, TReadOnlyValue> where TValue : TReadOnlyValue 
{ 
    private IDictionary<TKey, TValue> _dictionary; 

    public ReadOnlyDictionaryWrapper(IDictionary<TKey, TValue> dictionary) 
    { 
     if (dictionary == null) throw new ArgumentNullException("dictionary"); 
     _dictionary = dictionary; 
    } 
    public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); } 

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

    public bool TryGetValue(TKey key, out TReadOnlyValue value) 
    { 
     TValue v; 
     var result = _dictionary.TryGetValue(key, out v); 
     value = v; 
     return result; 
    } 

    public IEnumerable<TReadOnlyValue> Values { get { return _dictionary.Values.Cast<TReadOnlyValue>(); } } 

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

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

    public IEnumerator<KeyValuePair<TKey, TReadOnlyValue>> GetEnumerator() 
    { 
     return _dictionary 
        .Select(x => new KeyValuePair<TKey, TReadOnlyValue>(x.Key, x.Value)) 
        .GetEnumerator(); 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 
+0

+1 मैंने ऐसा कुछ किया जब मुझे एक ऐसे शब्दकोश की आवश्यकता थी जिसमें उत्परिवर्तनीय और अपरिवर्तनीय विचार दोनों हों। –

+0

यह एक शब्दकोश के एक पाठपूर्ण दृश्य की तरह है। शब्दकोश स्वयं भी बदल सकता है। – vidstige

+0

@ vidstige, "शब्दकोश स्वयं भी बदल सकता है" - बेशक, यही कारण है कि यह निजी है। – Joe

0

हो सकता है कि यह समाधान आप के लिए काम करता है:

public class ExposesReadOnly 
{ 
    private IDictionary<int, IReadOnly> InternalDict { get; set; } 
    public IReadOnlyDictionary<int, IReadOnly> PublicList 
    { 
     get 
     { 
      IReadOnlyDictionary<int, IReadOnly> dictionary = new ReadOnlyDictionary<int, IReadOnly>(InternalDict); 

      return dictionary; 
     } 
    } 

    private class NotReadOnly : IReadOnly 
    { 
     public string Name { get; set; } 
    } 

    public void AddSomeValue() 
    { 
     InternalDict = new Dictionary<int, NotReadOnly>(); 
     InternalDict.Add(1, new NotReadOnly() { Name = "SomeValue" }); 
    } 
} 

public interface IReadOnly 
{ 
    string Name { get; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     ExposesReadOnly exposesReadOnly = new ExposesReadOnly(); 
     exposesReadOnly.AddSomeValue(); 

     Console.WriteLine(exposesReadOnly.PublicList[1].Name); 
     Console.ReadLine(); 

     exposesReadOnly.PublicList[1].Name = "This is not possible!"; 
    } 
} 

आशा इस मदद करता है!

स्वागत करती है

+0

वह मूल्य जोड़ने के लिए काम करता है, लेकिन मैं उन्हें आंतरिक रूप से भी एक्सेस करता हूं और उन्हें अपडेट करता हूं। यही वह जगह है जहां मैं सूचीबद्ध विकल्प # 3 के साथ खड़ा था, क्योंकि जब मैं उन्हें आंतरिक रूप से पुनर्प्राप्त करता हूं तो मुझे केवल पढ़ने के लिए वापस जाना होगा। – Ocelot20

+0

मैंने जो समाधान दिया है, उसके साथ आप पूरी तरह से एक्सेस, अपडेट, डिलीट, एड इत्यादि कर सकते हैं।कक्षा के अंदर से शब्दकोश में कोई भी मूल्य और केवल इसे केवल एक पठनीय शब्दकोश के रूप में उजागर करता है। कृपया एक ठोस उदाहरण दें जहां यह कोड पर्याप्त नहीं हो सकता है, इसलिए मैं आपकी समस्या को और अधिक स्पष्ट रूप से समझ सकता हूं। –

+0

'आंतरिक डिक्ट [1] .नाम =" कुछ नया वैल्यू "एक कलाकार के बिना काम नहीं करेगा। – Ocelot20

1

मेरा सुझाव है कि आप अपने खुद के covariant इंटरफेस निर्धारित कर सकते हैं, और covariant पहुँच तरीकों में शामिल साथ ही एक विधि जो केवल पढ़ने-योग्य रैपर ऑब्जेक्ट तैयार करेगी जो वांछित प्रकारों के साथ IDictionary या IReadonlyDictionary लागू करती है। बस अपने इंटरफेस के भीतर IEnumerable<KeyValuePair<TKey,TValue>> अनदेखा करें। (एक वस्तु उदाहरण दिया

आप क्या कर रहे पर निर्भर करता है, यह एक IFetchByKey<out TValue> जो वस्तु के किसी भी प्रकार के लिए पूर्व को स्वीकार प्रश्नों के साथ IFetchByKey<in TKey, out TValue> द्वारा विरासत में मिली है, परिभाषित करने के लिए सहायक हो सकता है, Cat का संग्रह करने के लिए सक्षम होना चाहिए कहें कि इसमें उस उदाहरण को शामिल किया गया है, भले ही यह Dog या ToyotaPrius है; संग्रह में बाद के प्रकारों का कोई भी उदाहरण नहीं होगा, और ऐसा कहने में सक्षम होना चाहिए)।

0

सहप्रसरण का एक विशिष्ट कमी के लिए एक और दृष्टिकोण:

एक IDictionary

public static class DictionaryExtensions 
    { 
     public static IReadOnlyDictionary<TKey, IEnumerable<TValue>> ToReadOnlyDictionary<TKey, TValue>(
      this IDictionary<TKey, List<TValue>> toWrap) 
     { 
      var intermediate = toWrap.ToDictionary(a => a.Key, a =>a.Value!=null? a.Value.ToArray().AsEnumerable():null); 
      var wrapper = new ReadOnlyDictionary<TKey, IEnumerable<TValue>>(intermediate); 
      return wrapper; 
     } 
    } 
0

पर उपयोगी सहप्रसरण की एक विशिष्ट प्रकार के लिए चारों ओर काम आपके उपयोग के मामले के आधार पर आप दूर के साथ प्राप्त करने में सक्षम हो सकता है Func<int,IReadOnly> का खुलासा करना।

public class ExposesReadOnly 
{ 
    private Dictionary<int, NotReadOnly> InternalDict { get; set; } 
    public Func<int,IReadOnly> PublicDictionaryAccess 
    { 
     get 
     { 
      return (x)=>this.InternalDict[x]; 
     } 
    } 

    // This class can be modified internally, but I don't want 
    // to expose this functionality. 
    private class NotReadOnly : IReadOnly 
    { 
     public string Name { get; set; } 
    } 
} 

public interface IReadOnly 
{ 
    string Name { get; } 
}