diff --git a/DeepClone.Test/DirectDictionaryOverloadTests.cs b/DeepClone.Test/DirectDictionaryOverloadTests.cs
new file mode 100644
index 0000000..e8c22a7
--- /dev/null
+++ b/DeepClone.Test/DirectDictionaryOverloadTests.cs
@@ -0,0 +1,81 @@
+// Copyright (c) 2023-2026 ktsu-dev contributors
+
+namespace ktsu.DeepClone.Test;
+
+using System.Collections.Immutable;
+
+///
+/// Tests that .DeepClone() can be called directly on dictionary types that implement both
+/// and , and that the
+/// result has the source's type and comparer (ktsu-dev/DeepClone#86). Each test calls the extension without
+/// a cast, so this file stops compiling if the overloads become ambiguous again.
+///
+[TestClass]
+public class DirectDictionaryOverloadTests
+{
+ private static readonly string[] DescendingKeys = ["c", "b", "a"];
+
+ ///
+ /// Tests that a sorted list clones to a sorted list with the source's comparer and deep-cloned values.
+ ///
+ [TestMethod]
+ public void SortedList_DeepClone_KeepsTypeComparerAndClonesValues()
+ {
+ Comparer descending = Comparer.Create((x, y) => string.CompareOrdinal(y, x));
+ SortedList original = new(descending)
+ {
+ ["a"] = new SimpleObject { Id = 1, Name = "A" },
+ ["c"] = new SimpleObject { Id = 3, Name = "C" },
+ };
+
+ SortedList clone = original.DeepClone();
+ clone["b"] = new SimpleObject { Id = 2, Name = "B" };
+
+ Assert.AreSame(descending, clone.Comparer);
+ Assert.AreSequenceEqual(DescendingKeys, clone.Keys);
+ Assert.AreNotSame(original["a"], clone["a"]);
+ Assert.AreEqual(1, clone["a"].Id);
+ }
+
+ ///
+ /// Tests that an immutable dictionary clones to an immutable dictionary with the source's key and value
+ /// comparers and deep-cloned values.
+ ///
+ [TestMethod]
+ public void ImmutableDictionary_DeepClone_KeepsTypeComparersAndClonesValues()
+ {
+ ImmutableDictionary original = ImmutableDictionary
+ .Create(StringComparer.OrdinalIgnoreCase, ReferenceEqualityComparer.Instance)
+ .Add("Key", new SimpleObject { Id = 1, Name = "One" });
+
+ ImmutableDictionary clone = original.DeepClone();
+
+ Assert.AreSame(StringComparer.OrdinalIgnoreCase, clone.KeyComparer);
+ Assert.AreSame(ReferenceEqualityComparer.Instance, clone.ValueComparer);
+ Assert.IsTrue(clone.ContainsKey("KEY"));
+ Assert.AreNotSame(original["Key"], clone["Key"]);
+ Assert.AreEqual(1, clone["Key"].Id);
+ }
+
+ ///
+ /// Tests that an immutable sorted dictionary clones to an immutable sorted dictionary with the source's
+ /// key and value comparers and deep-cloned values.
+ ///
+ [TestMethod]
+ public void ImmutableSortedDictionary_DeepClone_KeepsTypeComparersAndClonesValues()
+ {
+ Comparer descending = Comparer.Create((x, y) => string.CompareOrdinal(y, x));
+ ImmutableSortedDictionary original = ImmutableSortedDictionary
+ .Create(descending, ReferenceEqualityComparer.Instance)
+ .Add("a", new SimpleObject { Id = 1, Name = "A" })
+ .Add("c", new SimpleObject { Id = 3, Name = "C" });
+
+ ImmutableSortedDictionary clone = original.DeepClone().Add("b", new SimpleObject { Id = 2, Name = "B" });
+
+ Assert.AreSame(descending, clone.KeyComparer);
+ Assert.AreSame(ReferenceEqualityComparer.Instance, clone.ValueComparer);
+ Assert.AreSequenceEqual(DescendingKeys, clone.Keys);
+ Assert.AreNotSame(original["a"], clone["a"]);
+ Assert.AreEqual(1, clone["a"].Id);
+ }
+}
diff --git a/DeepClone/DeepCloneContainerExtensions.cs b/DeepClone/DeepCloneContainerExtensions.cs
index 1f677e8..09b84aa 100644
--- a/DeepClone/DeepCloneContainerExtensions.cs
+++ b/DeepClone/DeepCloneContainerExtensions.cs
@@ -255,6 +255,86 @@ public static SortedDictionary DeepClone(this Sorted
return clone;
}
+ ///
+ /// Deep clones a sorted list, keeping its key comparer.
+ ///
+ /// The type of keys in the list.
+ /// The type of values in the list.
+ /// The source list to clone.
+ /// A new sorted list with the source's comparer, containing deep clones of the keys and values
+ /// if they implement IDeepCloneable, otherwise containing the original keys and values.
+ ///
+ /// implements both and
+ /// , so this overload is also what lets
+ /// sortedList.DeepClone() compile without a cast.
+ ///
+ /// Thrown if source is null.
+ public static SortedList DeepClone(this SortedList source)
+ where TKey : notnull
+ {
+ Ensure.NotNull(source);
+
+ SortedList clone = new(source.Count, source.Comparer);
+ AddClonedPairs(clone, source);
+ return clone;
+ }
+
+#if NET
+ ///
+ /// Deep clones an immutable dictionary, keeping its key and value comparers.
+ ///
+ /// The type of keys in the dictionary.
+ /// The type of values in the dictionary.
+ /// The source dictionary to clone.
+ /// A new immutable dictionary with the source's comparers, containing deep clones of the keys and values
+ /// if they implement IDeepCloneable, otherwise containing the original keys and values.
+ ///
+ /// implements both and
+ /// , so this overload is also what lets
+ /// immutableDictionary.DeepClone() compile without a cast.
+ ///
+ /// Thrown if source is null.
+ public static ImmutableDictionary DeepClone(this ImmutableDictionary source)
+ where TKey : notnull
+ {
+ Ensure.NotNull(source);
+
+ return ImmutableDictionary.CreateRange(source.KeyComparer, source.ValueComparer, ClonePairs(source));
+ }
+
+ ///
+ /// Deep clones an immutable sorted dictionary, keeping its key and value comparers.
+ ///
+ /// The type of keys in the dictionary.
+ /// The type of values in the dictionary.
+ /// The source dictionary to clone.
+ /// A new immutable sorted dictionary with the source's comparers, containing deep clones of the keys and
+ /// values if they implement IDeepCloneable, otherwise containing the original keys and values.
+ ///
+ /// implements both
+ /// and , so this overload is also what lets
+ /// immutableSortedDictionary.DeepClone() compile without a cast.
+ ///
+ /// Thrown if source is null.
+ public static ImmutableSortedDictionary DeepClone(this ImmutableSortedDictionary source)
+ where TKey : notnull
+ {
+ Ensure.NotNull(source);
+
+ return ImmutableSortedDictionary.CreateRange(source.KeyComparer, source.ValueComparer, ClonePairs(source));
+ }
+
+ ///
+ /// Deep clones the key and value of each pair.
+ ///
+ /// The type of the keys.
+ /// The type of the values.
+ /// The key-value pairs to clone.
+ /// The cloned pairs.
+ private static IEnumerable> ClonePairs(IEnumerable> pairs) =>
+ pairs.Select(p => new KeyValuePair(DeepClone(p.Key), DeepClone(p.Value)));
+#endif
+
///
/// Deep clones a concurrent dictionary, keeping its key comparer where the target framework exposes it.
///
diff --git a/README.md b/README.md
index 9feccba..0c197b2 100644
--- a/README.md
+++ b/README.md
@@ -603,13 +603,14 @@ Extension methods for deep cloning various container types.
| `DeepClone` | `IEnumerable?` | Creates a deep clone of an enumerable collection |
| `DeepClone` | `IDictionary?` | Creates a deep clone of a dictionary, preserving the key comparer where the runtime type exposes one |
| `DeepClone` | `IReadOnlyDictionary?` | Creates a deep clone of a read-only dictionary, preserving the key comparer where the runtime type exposes one |
+| `DeepClone` | `SortedList` | Creates a deep clone of a sorted list, preserving the key comparer |
| `DeepClone` | `HashSet?` | Creates a deep clone of a hash set, preserving the comparer |
| `DeepClone` | `SortedSet?` | Creates a deep clone of a sorted set, preserving the comparer |
| `DeepClone` | `Stack?` | Creates a deep clone of a stack, preserving the element order |
| `DeepClone` | `ImmutableArray` | Creates a deep clone of an immutable array |
| `DeepClone` | `ImmutableList` | Creates a deep clone of an immutable list |
-| `DeepClone` | `ImmutableDictionary` | Creates a deep clone of an immutable dictionary |
-| `DeepClone` | `ImmutableSortedDictionary` | Creates a deep clone of an immutable sorted dictionary |
+| `DeepClone` | `ImmutableDictionary` | Creates a deep clone of an immutable dictionary, preserving the key and value comparers (.NET only) |
+| `DeepClone` | `ImmutableSortedDictionary` | Creates a deep clone of an immutable sorted dictionary, preserving the key and value comparers (.NET only) |
| `DeepClone` | `ImmutableHashSet` | Creates a deep clone of an immutable hash set |
| `DeepClone` | `ImmutableSortedSet` | Creates a deep clone of an immutable sorted set |
| `DeepClone` | `ImmutableStack` | Creates a deep clone of an immutable stack |