Concrete implementations of IDictionary<K, V>
and IReadOnlyDictionary<K, V>
do not provide Empty
singletons, per those for Array.Empty
and Enumerable.Empty
.
This proposal would permit the same idiom to be available for Dictionary
.
This is a nice-to-have, but helps in environments where resources are constrained. The current idiom is to create a new Dictionary<K, V>(0)
but that incurs not-insignificant private state, and the semantics of 'immutably empty' are different to those for 'empty but not populated yet'.
There are several data structures that build up maps of maps, for example System.Json
. In scenarios where datasets are large, the cost and semantics of pseudo-empty
add up.
For scenarios where we have lists instead of maps, we already use Array.Empty<T>
or Enumerable.Empty<T>
. It would be consistent to provide the same facility for maps.
```C#
var empty = Dictionary.Empty
empty.Count; // 0
empty.IsReadOnly; // true
empty["hi"]; // KeyNotFound or InvalidOperation (?)
empty.Add(...); // InvalidOperation
Keys; // Array.Empty
# Proposed API
```C#
public static class Dictionary // See open questions
{
/// <summary>
/// Returns an empty dictionary that is immutable.
/// </summary>
/// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
/// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
/// <returns>Returns an empty <see cref="IDictionary{TKey, TValue}".</returns>
public static IDictionary<TKey, TValue> Empty<TKey, TValue>() => <singleton impl>;
}
public static class ReadOnlyDictionary
{
/// <summary>
/// Returns an empty dictionary that is immutable.
/// </summary>
/// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
/// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
/// <returns>Returns an empty <see cref="IReadOnlyDictionary{TKey, TValue}".</returns>
public static IReadOnlyDictionary<TKey, TValue> ReadOnlyEmpty<TKey, TValue>() => <singleton impl>;
}
The singletons would return sensible defaults where possible for getters, though indexers would need to throw. Since IsReadOnly==true
, mutators should throw too.
All errors should align with those used when a traditional Dictionary
has 'IsReadOnly=true`.
public static class Dictionary
to host the Empty
singleton. Ditto for ReadOnlyDictionary
.Dictionary.Empty
might surprise or confuse users, but if we set IsReadOnly=true
then it should cause less friction. ReadOnlyDictionary.Empty
is already expected to be immutable, so it should not have the same problem.Prototype comprises 3 classes; ReadOnlyDictionary class, Dictionary class and Singleton implementation.
I am happy to contribute the PR, when/if we gain consensus
Happy to PR, but would especially need guidance on namespace, naming, decision on immutability.
@grant-d your API proposals are welcome, but could you please format them into sections as suggested in example linked from https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/api-review-process.md?
The standard format greatly helps the review process.
No problem - let me know if this update is suitable
cool, as for any issue, if you don't get a response from area owner in a few days, you can ping them: https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/issue-guide.md
@safern or聽@ianhays please comment on tis proposal.
This already exists, the method is called ImmutableDictionary.Create<TKey, TValue>()
(or ImmutableDictionary<TKey, TValue>.Empty
). The returned type implements both IDictionary<TKey, TValue>
and IReadOnlyDictionary<TKey, TValue>
. I'm not sure what would be the point of creating another version of that method under a different name.
Thanks svick, I had looked in various places for such functionality, but missed ImmutableDictionary.
Most helpful comment
This already exists, the method is called
ImmutableDictionary.Create<TKey, TValue>()
(orImmutableDictionary<TKey, TValue>.Empty
). The returned type implements bothIDictionary<TKey, TValue>
andIReadOnlyDictionary<TKey, TValue>
. I'm not sure what would be the point of creating another version of that method under a different name.