Skip to content

GetOrCreate(key, defaultValue) won't compile for string, interface or other non-new()-able value types (CS0310) #139

Description

@matt-edmondson

What's wrong

The explicit-default overloads of GetOrCreate carry a new() constraint they never use:

  • Extensions/DictionaryExtensions.cs ~L31 — GetOrCreate<TKey, TVal>(this IDictionary<TKey, TVal>, TKey key, TVal defaultValue) where TVal : notnull, new()
  • Extensions/DictionaryExtensions.cs ~L101 — GetOrCreate<TKey, TVal>(this ConcurrentDictionary<TKey, TVal>, TKey key, TVal defaultValue) where TVal : new()

Both insert the caller-supplied defaultValue and never call new TVal(). The constraint looks copied from the one-argument GetOrCreate(key) overloads, which do need it.

Failure scenario

Each of these fails to compile with CS0310 ("'string' must be a non-abstract type with a public parameterless constructor…"), verified in a probe project against the net9.0 build:

new Dictionary<int, string>().GetOrCreate(1, "one");
new ConcurrentDictionary<int, string>().GetOrCreate(1, "one");
new Dictionary<int, IList<int>>().GetOrCreate(1, new List<int>());

So the overload whose whole point is "I'll supply the value" is unusable for strings, interfaces, abstract types, and records/classes without a parameterless constructor — the cases where the one-argument form can't help either.

Suggested fix

Remove new() from both three-argument overloads (keep notnull on TKey/TVal and the existing runtime null checks). Leave new() on the one-argument overloads. Relaxing a generic constraint is source-compatible for existing callers.

Acceptance criteria

  • The three calls above compile and behave as expected (insert when missing, return existing value otherwise).
  • Tests added for string and an interface-typed value on both IDictionary and ConcurrentDictionary.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions