Make dictionary read only in C#

后端 未结 6 809
一向
一向 2020-12-18 20:37

I have a Dictionary> and would like to expose the member as read only. I see that I can return it as a IReadOnlyDictionar

相关标签:
6条回答
  • 2020-12-18 21:01

    I run into the same problem. I solved it on the following way.

    List<string> list = new List<string>();
    
    Dictionary<string, IReadOnlyCollection<string>> dic = new Dictionary<string, IReadOnlyCollection<string>>();
    
    IReadOnlyDictionary<string, IReadOnlyCollection<string>> dicRo = new ReadOnlyDictionary<string, IReadOnlyCollection<string>>(dic);
    
     list.Add("Test1");
    
     dic["T"] = list.AsReadOnly();
    
     ist.Add("Test2");
    

    This has the positiv effekt, that you

    • can still add items to the list
    • can still add items to the dictionary
    • can't edit the ReadOnlyDictionary
    • can't edit the ReadOnlyCollection
    • can't cast it into a Dictionary
    • can't cast it into a List
    • have your ReadOnlyDictionary always up to date

    Maybe this will help someone.

    0 讨论(0)
  • 2020-12-18 21:05

    Given the fact that you're specifically looking for a read-only Dictionary<string, List<string>>, you're basically looking exactly for a Lookup.

    The Dictionary object has a ToLookup() extension.

    0 讨论(0)
  • 2020-12-18 21:05

    If you want to return a read only dictionary but still be able to mutate the dictionary and list in your class you could use casting to get back the list type.

    This example is a bit contrived, but shows how it could work.

    public class MyClass
    {
        Dictionary<string, IReadOnlyList<string>> _dictionary;
        public IReadOnlyDictionary<string, IReadOnlyList<string>> Dictionary { get { return _dictionary; } }
    
        public MyClass()
        {
            _dictionary = new Dictionary<string, IReadOnlyList<string>>();
        }
    
        public void AddItem(string item)
        {
            IReadOnlyList<string> readOnlyList = null;
            List<string> list = null;
            if (!_dictionary.TryGetValue(item, out readOnlyList))
            {
                list = new List<string>();
                _dictionary.Add(item, list);
            }
            else
                list = readOnlyList as List<string>;
            list.Add(item);
        }
    }
    

    If you goal is to have the property be immutable, then using a ReadOnlyDictionary would be the best option.

    0 讨论(0)
  • 2020-12-18 21:15

    First, you'll have to create a new dictionary with the desired content types:

    var dicWithReadOnlyList = dic.ToDictionary(
        kv => kv.Key,
        kv => kv.Value.AsReadOnly());
    

    Then you can just return the new dictionary, since IReadOnlyDictionary is a supertype of Dictionary.


    Why do you need to do that? Because Dictionary<T, A> is not a supertype of Dictionary<T, B>, even if A is a supertype of B. Why? Consider the following example:

    var dic = new Dictionary<T, B>();
    Dictionary<T, A> dic2 = dic;      // Imagine this were possible...
    
    dic2.Add(someT, someA);           // ...then we'd have a type violation here, since
                                      // dic2 = dic requires some B as the value.
    

    In other words, TValue in Dictionary is not covariant. From an object-orientied point of view, covariance should be possible in the read-only version of the dictionary, but there are legacy issues in the .NET framework which prevent this (see the part starting with "UPDATE" in this question for details).

    0 讨论(0)
  • 2020-12-18 21:18

    It would be as easy as casting the whole dictionary reference to IReadOnlyDictionary<string, IReadOnlyList<string>> because Dictionary<TKey, TValue> implements IReadOnlyDictionary<TKey, TValue>.

    BTW, you can't do that because you want the List<string> values as IReadOnlyList<string>.

    So you need something like this:

    var readOnlyDict = (IReadOnlyDictionary<string, IReadOnlyList<string>>)dict.ToDictionary(pair => pair.Key, pair => pair.Value.AsReadOnly());
    

    Immutable dictionaries

    This is just a suggestion, but if you're looking for immutable dictionaries, add System.Collections.Immutable NuGet package to your solution and you'll be able to use them:

    // ImmutableDictionary<string, ImmutableList<string>>
    var immutableDict = dict.ToImmutableDictionary(pair => pair.Key, pair => pair.Value.ToImmutableList());
    

    Learn more about Immutable Collections here.

    0 讨论(0)
  • 2020-12-18 21:22

    https://msdn.microsoft.com/en-us/library/acdd6hb7.aspx

    You can use this to expose the object as readonly.

    You could also use properties get; set; and only allow the get to be public.

    But Matias answer seems to be more fitting.

    0 讨论(0)
提交回复
热议问题