问题
I have a Dictionary<string, List<string>> and would like to expose the member as read only. I see that I can return it as a IReadOnlyDictionary<string, List<string>>, but I can't figure out how to return it as an IReadOnlyDictionary<string, IReadOnlyList<string>>.
Is there a way to do this? In c++ I'd just be using const, but C# doesn't have that.
Note that simply using a IReadOnlyDictionary does not help in this case, because I want the values to be read only as well. It appears the only way to do this is build another IReadOnlyDictionary, and add IReadOnlyList to them.
Another option, which I wouldn't be thrilled with, would be to create wrapper which implements the interface IReadOnlyDictionary>, and have it hold a copy of the original instance, but that seems overkill.
回答1:
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.
回答2:
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.
回答3:
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).
回答4:
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.
回答5:
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.
来源:https://stackoverflow.com/questions/39086520/make-dictionary-read-only-in-c-sharp