I've recently just noticed that IDictionary does not implement IReadOnlyDictionary. I'm using two third-party libraries, one of which provides a ToDictionary()
method which returns an IDictionary containing the contents, and another which consumes an IReadOnlyDictionary. In order to make this work, I've had to write the following ugly code:
// IDictionary does not implement IReadOnlyDictionary, so we have to call .ToDictionary()
// again to get a concrete dictionary implementation.
var errors = result.ToDictionary().ToDictionary(x => x.Key, x => x.Value);
From looking at the two interfaces, it seems that the methods in IReadOnlyDictionary
are a direct subset of IDictionary
:
// Represents a generic read-only collection of key/value pairs.
public interface IReadOnlyDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IReadOnlyCollection<KeyValuePair<TKey, TValue>>
{
TValue this[TKey key] { get; }
IEnumerable<TKey> Keys { get; }
IEnumerable<TValue> Values { get; }
bool ContainsKey(TKey key);
bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value);
}
// Represents a generic collection of key/value pairs.
public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
{
TValue this[TKey key] { get; set; }
ICollection<TKey> Keys { get; }
ICollection<TValue> Values { get; }
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
bool Remove(TKey key);
bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value);
}
Some notable differences:
- The array index operator is
get
in the read-only version, andget/set
in the writeable version. Would it be possible to specify this if inheriting from IReadOnlyDictionary? - The
Keys
andValues
are IEnumerable in the read-only version, and ICollection in the writeable version. This also doesn't make sense to me. When would you add a key to a dictionary without a value, or add a value to a dictionary without a key? I feel like it would make more sense for the writeable dictionary to also return IEnumerable or IReadOnlyCollection for these properties.
The .Net team put a lot of thought into the core classes, so I assume the interfaces are separate by design. Does anyone know why the interfaces were created this way?