Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions DeepClone.Test/SpecializedCollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,62 @@ public void HashSet_DeepClone_ShouldCreateIndependentCopy()
Assert.AreEqual("Item1", originalItem.Name);
}

/// <summary>
/// Tests deep cloning an IReadOnlyDictionary.
/// </summary>
[TestMethod]
public void ReadOnlyDictionary_DeepClone_ShouldCreateIndependentCopy()
{
// Arrange
Dictionary<string, SimpleObject> original = new()
{
["a"] = new() { Id = 1, Name = "Item1" },
["b"] = new() { Id = 2, Name = "Item2" }
};

// Act
IReadOnlyDictionary<string, SimpleObject> clone = ((IReadOnlyDictionary<string, SimpleObject>)original).DeepClone();

// Assert
Assert.IsNotNull(clone);
Assert.HasCount(original.Count, clone);
Assert.AreEqual(1, clone["a"].Id);
Assert.AreEqual("Item2", clone["b"].Name);
Assert.AreNotSame(original["a"], clone["a"]);

// Verify independence
clone["a"].Name = "Modified";
Assert.AreEqual("Item1", original["a"].Name);
}

/// <summary>
/// Tests deep cloning an empty IReadOnlyDictionary.
/// </summary>
[TestMethod]
public void ReadOnlyDictionary_DeepClone_Empty_ShouldReturnEmptyDictionary()
{
// Arrange
Dictionary<string, int> original = [];

// Act
IReadOnlyDictionary<string, int> clone = ((IReadOnlyDictionary<string, int>)original).DeepClone();

// Assert
Assert.IsNotNull(clone);
Assert.IsEmpty(clone);
}

/// <summary>
/// Tests that deep cloning a null IReadOnlyDictionary throws.
/// </summary>
[TestMethod]
public void ReadOnlyDictionary_DeepClone_Null_ShouldThrow()
{
IReadOnlyDictionary<string, int> original = null!;

Assert.ThrowsExactly<ArgumentNullException>(() => original.DeepClone());
}

/// <summary>
/// Tests deep cloning a SortedSet.
/// </summary>
Expand Down
11 changes: 9 additions & 2 deletions DeepClone/DeepCloneContainerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
/// of individual elements. It checks if the object implements IDeepCloneable and calls
/// DeepClone() if it does, otherwise it returns the original object.
/// </remarks>
private static T DeepClone<T>(T source) => source == null ? default! : source is IDeepCloneable cloneable ? (T)cloneable.DeepClone() : source;

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Extract this nested ternary operation into an independent statement.

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Extract this nested ternary operation into an independent statement.

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Use a comparison to 'default(T)' instead or add a constraint to 'T' so that it can't be a value type.

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Use a comparison to 'default(T)' instead or add a constraint to 'T' so that it can't be a value type.

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Extract this nested ternary operation into an independent statement.

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Extract this nested ternary operation into an independent statement.

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Use a comparison to 'default(T)' instead or add a constraint to 'T' so that it can't be a value type.

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Extract this nested ternary operation into an independent statement.

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Use a comparison to 'default(T)' instead or add a constraint to 'T' so that it can't be a value type.

Check warning on line 97 in DeepClone/DeepCloneContainerExtensions.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Extract this nested ternary operation into an independent statement.

/// <summary>
/// Deep clones a collection of objects.
Expand Down Expand Up @@ -160,9 +160,16 @@
/// var clonedReadOnlyDict = originalReadOnlyDict.DeepClone();
/// </code>
/// </remarks>
/// <exception cref="ArgumentNullException">Thrown if source is null.</exception>
public static IReadOnlyDictionary<TKey, TValue> DeepClone<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> source)
where TKey : notnull =>
(IReadOnlyDictionary<TKey, TValue>)source.ToDictionary(DeepClone, DeepClone);
where TKey : notnull
{
Ensure.NotNull(source);

return source.ToDictionary(
pair => DeepClone(pair.Key),
pair => DeepClone(pair.Value));
}

/// <summary>
/// Deep clones a hash set.
Expand Down
Loading