Skip to content

Proposal: (I)Dictionary<TK,TV>.GetValueOrDefault #15290

@Eilon

Description

@Eilon

Scenario

In almost every app or library I write I almost always end up needing to write code like this, in at least one place:

SomeClass returnValue;
return DictionaryOfSomeClass.TryGetValue(someKey, out returnValue) ? returnValue : null;

The reason that the IDictionary<TKey, TValue> contract throws from its indexer for a non-existent key are well-known: an alternative behavior of returning null is nonsensical if TValue is a value type. Returning default(TValue) would work, but would clearly be a misleading behavior.

But with dictionaries of class-types it is often desirable and expected to return null for a non-existent key.

Proposal

namespace System.Collections.Generic
{
    public class Dictionary<TKey, TValue>
    {
        public TValue GetValueOrDefault(TKey key);
        public TValue GetValueOrDefault(TKey key, TValue defaultValue);
    }

    public static class CollectionExtensions
    {
        public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key);
        public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue);

        public static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key);
        public static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue);
    }
}

Notes:

  • There will be source-compile problem with ambiguity in all projects that already have such custom extension method GetValueOrDefault on IDictionary or IReadOnlyDictionary. Which is general problem for any extension method we add into CoreFX.

Original Proposal - replaced by the one above

I propose the following extension method (I don't like the name GetValueNoThrow, so that can be ignored for now). Please note that it applies only when TValue is a class, so it does not violate any behavior for value types.

    public static class ClassyDictionaryExtensions
    {
        public static TValue GetValueNoThrow_Ignore_The_Name<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
            where TValue : class
        {
            if (dictionary == null)
            {
                throw new ArgumentNullException(nameof(dictionary));
            }
            TValue value;
            dictionary.TryGetValue(key, out value);
            return value;
        }
    }

The new code would end up with one very-easy-to-read line of code:

            return DictionaryOfSomeClass.GetValueNoThrow(someKey);

Discussion

Would others find such an extension method useful?

Metadata

Metadata

Assignees

Labels

api-approvedAPI was approved in API review, it can be implementedarea-System.Collectionshelp wanted[up-for-grabs] Good issue for external contributorswishlistIssue we would like to prioritize, but we can't commit we will get to it yet

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions