What's wrong
DeepCloneContainerExtensions has two dictionary extensions:
DeepClone(this IDictionary<TKey,TValue>) (line 137)
DeepClone(this IReadOnlyDictionary<TKey,TValue>) (line 164)
Dictionary<,>, SortedDictionary<,>, ConcurrentDictionary<,> and ReadOnlyDictionary<,> all implement both interfaces. For these types neither overload is better than the other, so the call is ambiguous and won't compile:
var d = new Dictionary<string,int>();
var c = d.DeepClone();
// error CS0121: The call is ambiguous between
// DeepCloneContainerExtensions.DeepClone<TKey,TValue>(IDictionary<TKey,TValue>) and
// DeepCloneContainerExtensions.DeepClone<TKey,TValue>(IReadOnlyDictionary<TKey,TValue>)
The XML doc example on the IDictionary overload (around line 133) shows this exact call: var clonedDict = originalDict.DeepClone();. The tests already work around the problem with explicit casts:
DeepClone.Test/DeepCloneTests.cs:317: "Cast to IDictionary to resolve ambiguity"
DeepClone.Test/SpecializedCollectionTests.cs:264: "explicit cast to IDictionary to resolve ambiguity"
In practice, anyone deep-cloning the most common dictionary type has to cast first.
Reproduction
Add var c = new Dictionary<string,int>().DeepClone(); to any file in a project that references the library. dotnet build fails with CS0121, naming both overloads.
Suggested fix
Add overloads for the concrete types, in the same style as the existing HashSet<T>, SortedSet<T> and Stack<T> overloads. The compiler prefers them over the interface overloads. They can also return the concrete type and keep the comparer, which fixes #77 for these types at the same time:
public static Dictionary<TKey,TValue> DeepClone<TKey,TValue>(this Dictionary<TKey,TValue> source) where TKey : notnull
{
Ensure.NotNull(source);
return source.ToDictionary(p => DeepClone(p.Key), p => DeepClone(p.Value), source.Comparer);
}
Add matching overloads for SortedDictionary<,> (keep Comparer) and ConcurrentDictionary<,>.
Acceptance: new Dictionary<string,int>().DeepClone() compiles and returns an independent Dictionary with the same comparer, and the cast workarounds in the tests can be removed.
What's wrong
DeepCloneContainerExtensionshas two dictionary extensions:DeepClone(this IDictionary<TKey,TValue>)(line 137)DeepClone(this IReadOnlyDictionary<TKey,TValue>)(line 164)Dictionary<,>,SortedDictionary<,>,ConcurrentDictionary<,>andReadOnlyDictionary<,>all implement both interfaces. For these types neither overload is better than the other, so the call is ambiguous and won't compile:The XML doc example on the
IDictionaryoverload (around line 133) shows this exact call:var clonedDict = originalDict.DeepClone();. The tests already work around the problem with explicit casts:DeepClone.Test/DeepCloneTests.cs:317: "Cast to IDictionary to resolve ambiguity"DeepClone.Test/SpecializedCollectionTests.cs:264: "explicit cast to IDictionary to resolve ambiguity"In practice, anyone deep-cloning the most common dictionary type has to cast first.
Reproduction
Add
var c = new Dictionary<string,int>().DeepClone();to any file in a project that references the library.dotnet buildfails with CS0121, naming both overloads.Suggested fix
Add overloads for the concrete types, in the same style as the existing
HashSet<T>,SortedSet<T>andStack<T>overloads. The compiler prefers them over the interface overloads. They can also return the concrete type and keep the comparer, which fixes #77 for these types at the same time:Add matching overloads for
SortedDictionary<,>(keepComparer) andConcurrentDictionary<,>.Acceptance:
new Dictionary<string,int>().DeepClone()compiles and returns an independentDictionarywith the same comparer, and the cast workarounds in the tests can be removed.