From 1f329973cf7c91072e8a1f4e1870274bad5f63b8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 27 Sep 2026 22:27:12 +0000 Subject: [PATCH] Drop the unused new() constraint from GetOrCreate(key, defaultValue) The IDictionary and ConcurrentDictionary overloads that take a default value insert the value the caller supplies and never construct one, but still required a parameterless constructor. Calls with a string, an interface or any type without one failed to compile with CS0310, which are exactly the cases the one-argument overload cannot serve either. Relaxing the constraint is source-compatible. The one-argument overloads keep new(), since they construct the value. Fixes #139 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LasidbyRZfyxgW8Z9wQu9M --- Extensions.Test/DictionaryExtensionsTests.cs | 46 ++++++++++++++++++++ Extensions/DictionaryExtensions.cs | 4 +- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Extensions.Test/DictionaryExtensionsTests.cs b/Extensions.Test/DictionaryExtensionsTests.cs index 216c544..e813ca4 100644 --- a/Extensions.Test/DictionaryExtensionsTests.cs +++ b/Extensions.Test/DictionaryExtensionsTests.cs @@ -42,6 +42,52 @@ public void GetOrCreateShouldAddAndReturnDefaultValue() Assert.AreEqual(99, dictionary["key1"]); } + // The overloads that take a default value never construct one, so they must not demand a + // parameterless constructor. Strings and interfaces have none, and these tests would not compile + // if the constraint came back. + + [TestMethod] + public void GetOrCreateWithDefaultShouldAcceptAStringValue() + { + Dictionary dictionary = []; + + Assert.AreEqual("one", dictionary.GetOrCreate(1, "one")); + Assert.AreEqual("one", dictionary.GetOrCreate(1, "uno")); + Assert.HasCount(1, dictionary); + } + + [TestMethod] + public void GetOrCreateWithDefaultShouldAcceptAnInterfaceValue() + { + Dictionary> dictionary = []; + List first = [1]; + + Assert.AreSame(first, dictionary.GetOrCreate(1, first)); + Assert.AreSame(first, dictionary.GetOrCreate(1, [])); + Assert.HasCount(1, dictionary); + } + + [TestMethod] + public void GetOrCreateConcurrentDictionaryWithDefaultShouldAcceptAStringValue() + { + ConcurrentDictionary dictionary = new(); + + Assert.AreEqual("one", dictionary.GetOrCreate(1, "one")); + Assert.AreEqual("one", dictionary.GetOrCreate(1, "uno")); + Assert.HasCount(1, dictionary); + } + + [TestMethod] + public void GetOrCreateConcurrentDictionaryWithDefaultShouldAcceptAnInterfaceValue() + { + ConcurrentDictionary> dictionary = new(); + List first = [1]; + + Assert.AreSame(first, dictionary.GetOrCreate(1, first)); + Assert.AreSame(first, dictionary.GetOrCreate(1, [])); + Assert.HasCount(1, dictionary); + } + [TestMethod] public void GetOrCreateConcurrentDictionaryShouldReturnExistingValue() { diff --git a/Extensions/DictionaryExtensions.cs b/Extensions/DictionaryExtensions.cs index 21ea1b4..14033ce 100644 --- a/Extensions/DictionaryExtensions.cs +++ b/Extensions/DictionaryExtensions.cs @@ -28,7 +28,7 @@ public static class DictionaryExtensions /// The key to get the value for. /// The default value to add when an existing value is not found. /// The value for the key if it exists, otherwise a new value. - public static TVal GetOrCreate(this IDictionary dictionary, TKey key, TVal defaultValue) where TKey : notnull where TVal : notnull, new() + public static TVal GetOrCreate(this IDictionary dictionary, TKey key, TVal defaultValue) where TKey : notnull where TVal : notnull { #pragma warning disable KTSU0004 // Use Ensure.NotNull instead of manual null check if (dictionary is null) @@ -98,7 +98,7 @@ public static class DictionaryExtensions /// The key to get the value for. /// The default value to add when an existing value is not found. /// The value for the key if it exists, otherwise a new value. - public static TVal GetOrCreate(this ConcurrentDictionary dictionary, TKey key, TVal defaultValue) where TKey : notnull where TVal : new() + public static TVal GetOrCreate(this ConcurrentDictionary dictionary, TKey key, TVal defaultValue) where TKey : notnull { #pragma warning disable KTSU0004 // Use Ensure.NotNull instead of manual null check if (dictionary is null)