Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
640 views
in Technique[技术] by (71.8m points)

c# - How to get around lack of covariance with IReadOnlyDictionary?

I'm trying to expose a read-only dictionary that holds objects with a read-only interface. Internally, the dictionary is write-able, and so are the objects within (see below example code). My problem is that IReadOnlyDictionary doesn't support covariant conversions because of the reason outlined in the question here. This means I can't just expose my internal dictionary as a read only one.

So my question is, is there an efficient way to convert my internal dictionary to an IReadOnlyDictionary, or some other way to handle this? The options I can think of are:

  1. Hold two internal dictionaries and keep them in sync.
  2. Create a new dictionary when the property is accessed and cast all the objects within.
  3. Cast the IReadOnly's back to NotReadOnly when using it internally.

1 seems like a pain, 2 seems highly inefficient. 3 sounds like the most promising at the moment, but is still ugly. Do I have any other options?

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; }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You could write your own read-only wrapper for the dictionary, e.g.:

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();
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...