{"id":26800603,"url":"https://github.com/ktsu-dev/deepclone","last_synced_at":"2026-02-16T05:04:08.989Z","repository":{"id":252169533,"uuid":"839632005","full_name":"ktsu-dev/DeepClone","owner":"ktsu-dev","description":null,"archived":false,"fork":false,"pushed_at":"2026-02-14T01:51:01.000Z","size":536,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-14T08:45:04.539Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ktsu-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":"COPYRIGHT.md","agents":null,"dco":null,"cla":null}},"created_at":"2024-08-08T02:41:46.000Z","updated_at":"2026-02-14T01:49:24.000Z","dependencies_parsed_at":"2024-09-06T12:12:04.129Z","dependency_job_id":"d8d8cf52-1d1b-452c-9bc9-3033eddf6900","html_url":"https://github.com/ktsu-dev/DeepClone","commit_stats":null,"previous_names":["ktsu-io/deepclone","ktsu-dev/deepclone"],"tags_count":106,"template":false,"template_full_name":null,"purl":"pkg:github/ktsu-dev/DeepClone","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FDeepClone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FDeepClone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FDeepClone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FDeepClone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ktsu-dev","download_url":"https://codeload.github.com/ktsu-dev/DeepClone/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ktsu-dev%2FDeepClone/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29500821,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T03:57:51.541Z","status":"ssl_error","status_checked_at":"2026-02-16T03:55:59.854Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-29T20:18:02.963Z","updated_at":"2026-02-16T05:04:08.960Z","avatar_url":"https://github.com/ktsu-dev.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ktsu.DeepClone\n\n\u003e A lightweight .NET library providing a simple, generic interface for implementing deep cloning functionality in your classes.\n\n[![License](https://img.shields.io/github/license/ktsu-dev/DeepClone)](https://github.com/ktsu-dev/DeepClone/blob/main/LICENSE.md)\n[![NuGet](https://img.shields.io/nuget/v/ktsu.DeepClone.svg)](https://www.nuget.org/packages/ktsu.DeepClone/)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/ktsu.DeepClone.svg)](https://www.nuget.org/packages/ktsu.DeepClone/)\n[![Build Status](https://github.com/ktsu-dev/DeepClone/workflows/build/badge.svg)](https://github.com/ktsu-dev/DeepClone/actions)\n[![GitHub Stars](https://img.shields.io/github/stars/ktsu-dev/DeepClone?style=social)](https://github.com/ktsu-dev/DeepClone/stargazers)\n\n## Introduction\n\nThe `ktsu.DeepClone` library defines the `IDeepCloneable` interface, which allows you to create deep copies of objects. The `DeepCloneable\u003cTDerived\u003e` base class implements this interface while providing type-safe cloning. This is particularly useful in scenarios where you need to duplicate an object while ensuring that its references to other objects are also fully cloned, not just copied.\n\nInspired by and based on the [ppy/osu!](https://github.com/ppy/osu) project's cloning utilities, this library is licensed under the MIT License.\n\n## Features\n\n- **Generic and Non-Generic Interfaces**: Works with any reference type (`class`)\n- **Deep Cloning**: Ensures that the cloned object is a completely independent copy, including all nested references\n- **Inheritance Support**: Easily implement deep cloning in class hierarchies\n- **Circular References**: Handles circular object references correctly without stack overflows or infinite loops\n- **Collection Extensions**: Deep clone collections including:\n  - Standard collections (List, Dictionary, Array)\n  - Specialized collections (HashSet, SortedSet, Stack, Queue, LinkedList)\n  - Concurrent collections (ConcurrentDictionary)\n  - Immutable collections (ImmutableArray, ImmutableList, ImmutableDictionary)\n- **Thread Safety**: Safe to use in multi-threaded environments\n- **Performance**: Designed for efficiency with minimal overhead\n- **Lightweight**: Minimal dependencies, focused on doing one thing well\n- **Simple Integration**: Easy to implement in your own classes\n- **Comprehensive Testing**: Extensive test coverage for reliability\n\n## Installation\n\n### Package Manager Console\n\n```powershell\nInstall-Package ktsu.DeepClone\n```\n\n### .NET CLI\n\n```bash\ndotnet add package ktsu.DeepClone\n```\n\n### Package Reference\n\n```xml\n\u003cPackageReference Include=\"ktsu.DeepClone\" Version=\"x.y.z\" /\u003e\n```\n\n## Usage Examples\n\n### Basic Example\n\n```csharp\nusing ktsu.DeepClone;\n\npublic class MyClass : DeepCloneable\u003cMyClass\u003e\n{\n    public int Value { get; set; }\n    public MyClass? NestedObject { get; set; }\n\n    protected override MyClass CreateInstance() =\u003e new MyClass();\n\n    protected override void DeepClone(MyClass clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        base.DeepClone(clone);\n        \n        clone.Value = this.Value;\n        clone.NestedObject = this.NestedObject?.DeepClone();\n    }\n}\n```\n\nYou can then create deep copies of your objects:\n\n```csharp\nvar original = new MyClass\n{\n    Value = 42,\n    NestedObject = new MyClass { Value = 84 }\n};\n\nvar copy = original.DeepClone();\n\n// The copy is a completely independent object\ncopy.Value = 100;\ncopy.NestedObject.Value = 200;\n\n// Original remains unchanged\nConsole.WriteLine(original.Value); // Outputs: 42\nConsole.WriteLine(original.NestedObject.Value); // Outputs: 84\n```\n\n### Understanding the Interface Structure\n\nThe library provides a non-generic interface for deep cloning:\n\n```csharp\n// Non-generic interface - Allows polymorphic cloning that returns object\npublic interface IDeepCloneable\n{\n    object DeepClone();\n}\n```\n\nThe `DeepCloneable\u003cTDerived\u003e` base class implements this interface while providing type-safe cloning through its generic implementation. This allows classes that inherit from it to have strongly-typed `DeepClone()` methods that return their specific type, while still supporting polymorphic cloning through the `IDeepCloneable` interface.\n\n### Using the DeepCloneable Base Class\n\nFor simpler implementation, you can use the provided `DeepCloneable\u003cTDerived\u003e` abstract class which implements the non-generic `IDeepCloneable` interface:\n\n```csharp\npublic class Person : DeepCloneable\u003cPerson\u003e\n{\n    public string? Name { get; set; }\n    public int Age { get; set; }\n    public List\u003cstring\u003e Interests { get; set; } = new();\n    \n    // Required: Create a new instance\n    protected override Person CreateInstance() =\u003e new Person();\n    \n    // Required: Copy your properties\n    protected override void DeepClone(Person clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        \n        clone.Name = Name;\n        clone.Age = Age;\n        \n        // For collections, use the DeepCloneFrom extension method\n        // This handles cloning of all elements in the collection\n        clone.Interests.DeepCloneFrom(Interests);\n    }\n}\n```\n\n### Understanding the Type-Safe CRTP Pattern\n\nThe library uses a C# implementation of the Curiously Recurring Template Pattern (CRTP) to provide type safety in inheritance hierarchies. This pattern allows derived classes to receive their actual concrete type in the `DeepClone` method without any casting.\n\n```csharp\n// The generic type parameter TDerived is the derived class itself\npublic abstract class DeepCloneable\u003cTDerived\u003e : IDeepCloneable\n    where TDerived : DeepCloneable\u003cTDerived\u003e\n{\n    // Public method that creates and returns a strongly typed clone\n    public TDerived DeepClone()\n    {\n        // Create a new instance of the derived type using an abstract factory method\n        TDerived clone = CreateInstance();\n        \n        // Call protected method to copy properties\n        DeepClone(clone);\n        \n        return clone;\n    }\n    \n    // Implementation of the non-generic interface\n    object IDeepCloneable.DeepClone() =\u003e DeepClone();\n\n    // To be implemented by derived classes to create instances of themselves\n    protected abstract TDerived CreateInstance();\n\n    // To be implemented by derived classes to copy properties\n    protected virtual void DeepClone(TDerived clone) { }\n}\n```\n\nWith this pattern:\n1. The `DeepClone()` method returns the exact type of the derived class\n2. The `DeepClone(TDerived clone)` method receives a parameter of the derived type, not the base type\n3. No casting is required in the derived class's implementation\n\nThis ensures complete type safety throughout the inheritance chain.\n\n### Inheritance and Deep Cloning\n\nWhen implementing deep cloning in a class hierarchy, it's critical to call `base.DeepClone()` first in derived classes:\n\n```csharp\n// Base class\npublic abstract class Shape\u003cT\u003e : DeepCloneable\u003cT\u003e where T : Shape\u003cT\u003e\n{\n    public int Id { get; set; }\n    public string? Name { get; set; }\n    public List\u003cstring\u003e Tags { get; set; } = new();\n    \n    protected override void DeepClone(T clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        \n        // Clone base class properties\n        clone.Id = Id;\n        clone.Name = Name;\n        \n        // Use DeepCloneFrom for collections\n        clone.Tags.DeepCloneFrom(Tags);\n    }\n}\n\n// Derived class\npublic class Circle : Shape\u003cCircle\u003e\n{\n    public double Radius { get; set; }\n    public Dictionary\u003cstring, double\u003e Measurements { get; set; } = new();\n    \n    protected override Circle CreateInstance() =\u003e new Circle();\n    \n    protected override void DeepClone(Circle clone)\n    {\n        // IMPORTANT: Always call base.DeepClone first to clone base properties\n        base.DeepClone(clone);\n        \n        // Then clone properties specific to this type\n        clone.Radius = Radius;\n        \n        // Use DeepCloneFrom for collections\n        clone.Measurements.DeepCloneFrom(Measurements);\n    }\n}\n\n// Further derived class\npublic class ColoredCircle : Circle\n{\n    public string? Color { get; set; }\n    public HashSet\u003cstring\u003e ColorGradients { get; set; } = new();\n    \n    protected override ColoredCircle CreateInstance() =\u003e new ColoredCircle();\n    \n    protected override void DeepClone(ColoredCircle clone)\n    {\n        // Call base first to handle Circle and Shape properties\n        base.DeepClone(clone);\n        \n        // Then clone ColoredCircle specific properties\n        clone.Color = Color;\n        \n        // Use DeepCloneFrom for collections\n        clone.ColorGradients.DeepCloneFrom(ColorGradients);\n    }\n}\n```\n\nNote that each derived class's `DeepClone()` method receives a parameter of its own type:\n- `Shape\u003cT\u003e.DeepClone(T clone)` receives a `T`\n- `Circle.DeepClone(Circle clone)` receives a `Circle`\n- `ColoredCircle.DeepClone(ColoredCircle clone)` receives a `ColoredCircle`\n\nThis is achieved through the CRTP pattern and means that no casting is needed in any of these methods.\n\nUsage:\n\n```csharp\nvar original = new ColoredCircle\n{\n    Id = 1,\n    Name = \"My Circle\",\n    Tags = { \"round\", \"geometric\" },\n    Radius = 10.5,\n    Measurements = { [\"diameter\"] = 21.0 },\n    Color = \"Blue\",\n    ColorGradients = { \"lightblue\", \"darkblue\" }\n};\n\nvar clone = original.DeepClone();\n\n// All properties from the entire hierarchy are cloned\nConsole.WriteLine(clone.Id);      // 1\nConsole.WriteLine(clone.Name);    // My Circle\nConsole.WriteLine(clone.Tags[0]); // round\nConsole.WriteLine(clone.Radius);  // 10.5\nConsole.WriteLine(clone.Color);   // Blue\n```\n\n### Polymorphic Deep Cloning with Common Ancestors\n\nWhen working with inheritance hierarchies that have multiple derived types from a common ancestor, you need to carefully implement deep cloning to maintain polymorphism. This is especially important when dealing with collections of different derived types.\n\nThe recommended approach is to use the CRTP pattern throughout the inheritance hierarchy along with interface hierarchies for polymorphism:\n\n```csharp\n// Non-generic interface for all animals to enable polymorphism\npublic interface IAnimal\n{\n    string? Name { get; set; }\n    int Age { get; set; }\n}\n\n// Base class in the hierarchy using CRTP pattern\npublic abstract class Animal\u003cTDerived\u003e : DeepCloneable\u003cTDerived\u003e, IAnimal\n    where TDerived : Animal\u003cTDerived\u003e\n{\n    public string? Name { get; set; }\n    public int Age { get; set; }\n\n    protected override void DeepClone(TDerived clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        base.DeepClone(clone);\n        clone.Name = Name;\n        clone.Age = Age;\n    }\n}\n\n// Interface for mammals, extending the animal interface\npublic interface IMammal : IAnimal\n{\n    int NumberOfLegs { get; set; }\n    string? FurColor { get; set; }\n}\n\n// Intermediate class for mammals, continuing the CRTP pattern\npublic abstract class Mammal\u003cTDerived\u003e : Animal\u003cTDerived\u003e, IMammal\n    where TDerived : Mammal\u003cTDerived\u003e\n{\n    public int NumberOfLegs { get; set; }\n    public string? FurColor { get; set; }\n\n    protected override void DeepClone(TDerived clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        base.DeepClone(clone);\n        clone.NumberOfLegs = NumberOfLegs;\n        clone.FurColor = FurColor;\n    }\n}\n\n// Interface for dogs\npublic interface IDog : IMammal\n{\n    string? Breed { get; set; }\n    bool IsTrained { get; set; }\n}\n\n// Concrete implementation - Dog\npublic class Dog : Mammal\u003cDog\u003e, IDog\n{\n    public string? Breed { get; set; }\n    public bool IsTrained { get; set; }\n\n    protected override Dog CreateInstance() =\u003e new Dog();\n\n    protected override void DeepClone(Dog clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        base.DeepClone(clone);\n        clone.Breed = Breed;\n        clone.IsTrained = IsTrained;\n    }\n}\n\n// Interface for cats\npublic interface ICat : IMammal\n{\n    bool IsIndoor { get; set; }\n    string? FavoriteToy { get; set; }\n}\n\n// Another concrete implementation - Cat\npublic class Cat : Mammal\u003cCat\u003e, ICat\n{\n    public bool IsIndoor { get; set; }\n    public string? FavoriteToy { get; set; }\n\n    protected override Cat CreateInstance() =\u003e new Cat();\n\n    protected override void DeepClone(Cat clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        base.DeepClone(clone);\n        clone.IsIndoor = IsIndoor;\n        clone.FavoriteToy = FavoriteToy;\n    }\n}\n\n// Container for a collection of polymorphic animals using the common interface\npublic class AnimalShelter : DeepCloneable\u003cAnimalShelter\u003e\n{\n    // Collection of animals using the common interface for polymorphism\n    public Collection\u003cIAnimal\u003e Animals { get; } = [];\n\n    protected override AnimalShelter CreateInstance() =\u003e new AnimalShelter();\n\n    protected override void DeepClone(AnimalShelter clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        base.DeepClone(clone);\n        clone.Animals.DeepCloneFrom(Animals);\n    }\n}\n```\n\nWith this approach:\n1. Each class in the hierarchy uses CRTP for type safety\n2. Each level has a corresponding interface (IAnimal, IMammal, IDog) for polymorphism\n3. No casting is needed in the DeepClone methods because of CRTP\n4. The AnimalShelter uses Collection\u003cIAnimal\u003e for polymorphic access to any animal type\n\nUsage example with different animal types:\n\n```csharp\n// Create animals\nvar dog = new Dog \n{ \n    Name = \"Buddy\", \n    Age = 3, \n    NumberOfLegs = 4, \n    FurColor = \"Golden\", \n    Breed = \"Labrador\", \n    IsTrained = true \n};\n\nvar cat = new Cat \n{ \n    Name = \"Whiskers\", \n    Age = 2, \n    NumberOfLegs = 4, \n    FurColor = \"Tabby\", \n    IsIndoor = true, \n    FavoriteToy = \"Mouse\" \n};\n\n// Create the shelter and add animals through the common interface\nvar shelter = new AnimalShelter();\nshelter.Animals.Add(dog);   // Adding a Dog as IAnimal\nshelter.Animals.Add(cat);   // Adding a Cat as IAnimal\n\n// Deep clone the shelter and all its animals\nvar clonedShelter = shelter.DeepClone();\n\n// The cloned animals maintain their concrete types through the interfaces\nvar clonedDog = clonedShelter.Animals[0] as Dog;  // Type checking with 'as'\nvar clonedCat = clonedShelter.Animals[1] as Cat;\n\n// Access specific derived type properties\nConsole.WriteLine(clonedDog?.Breed);        // \"Labrador\"\nConsole.WriteLine(clonedCat?.FavoriteToy);  // \"Mouse\"\n\n// Modifying the clone doesn't affect the original\nclonedDog!.Breed = \"Golden Retriever\";\nclonedCat!.FavoriteToy = \"Ball\";\n\nConsole.WriteLine(dog.Breed);        // Still \"Labrador\"\nConsole.WriteLine(cat.FavoriteToy);  // Still \"Mouse\"\n```\n\n### Working with Immutable Collections\n\nImmutable collections require special handling. The library provides extension methods for common immutable collection types:\n\n```csharp\npublic class DocumentWithImmutables : DeepCloneable\u003cDocumentWithImmutables\u003e\n{\n    public string? Title { get; set; }\n    public ImmutableArray\u003cstring\u003e Keywords { get; set; }\n    public ImmutableList\u003cReference\u003e References { get; set; }\n    public ImmutableDictionary\u003cstring, Author\u003e Authors { get; set; }\n    \n    protected override DocumentWithImmutables CreateInstance() =\u003e new DocumentWithImmutables();\n    \n    protected override void DeepClone(DocumentWithImmutables clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        \n        clone.Title = Title;\n        \n        // For immutable collections of value types, direct assignment is fine\n        clone.Keywords = Keywords;\n        \n        // For immutable collections of reference types, use DeepClone extension method\n        clone.References = References.DeepClone();\n        clone.Authors = Authors.DeepClone();\n    }\n}\n\npublic class Reference : DeepCloneable\u003cReference\u003e\n{\n    public string? Citation { get; set; }\n    public int Year { get; set; }\n    \n    protected override Reference CreateInstance() =\u003e new Reference();\n    \n    protected override void DeepClone(Reference clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        \n        clone.Citation = Citation;\n        clone.Year = Year;\n    }\n}\n\npublic class Author : DeepCloneable\u003cAuthor\u003e\n{\n    public string? Name { get; set; }\n    \n    protected override Author CreateInstance() =\u003e new Author();\n    \n    protected override void DeepClone(Author clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        \n        clone.Name = Name;\n    }\n}\n```\n\n### Advanced Usage with Collections\n\n```csharp\npublic class ComplexObject : DeepCloneable\u003cComplexObject\u003e\n{\n    public string? Name { get; set; }\n    public List\u003cItemObject\u003e Items { get; set; } = new();\n    public Dictionary\u003cstring, DataObject\u003e DataMapping { get; set; } = new();\n    public HashSet\u003cint\u003e UniqueIds { get; set; } = new();\n\n    protected override ComplexObject CreateInstance() =\u003e new ComplexObject();\n    \n    protected override void DeepClone(ComplexObject clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        \n        clone.Name = Name;\n\n        // Use DeepCloneFrom for all collections - this handles cloning correctly\n        clone.Items.DeepCloneFrom(Items);\n        clone.DataMapping.DeepCloneFrom(DataMapping);\n        \n        // Even for value type collections, DeepCloneFrom can be used for consistency\n        // This is equivalent to copying each element manually\n        clone.UniqueIds.DeepCloneFrom(UniqueIds);\n    }\n}\n\npublic class ItemObject : DeepCloneable\u003cItemObject\u003e\n{\n    public int Id { get; set; }\n    public string? Description { get; set; }\n\n    protected override ItemObject CreateInstance() =\u003e new ItemObject();\n    \n    protected override void DeepClone(ItemObject clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        \n        clone.Id = Id;\n        clone.Description = Description;\n    }\n}\n\npublic class DataObject : DeepCloneable\u003cDataObject\u003e\n{\n    public byte[]? Data { get; set; }\n\n    protected override DataObject CreateInstance() =\u003e new DataObject();\n    \n    protected override void DeepClone(DataObject clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        \n        // For arrays, create a new copy\n        clone.Data = Data?.ToArray();\n    }\n}\n```\n\n## API Reference\n\n### `IDeepCloneable` Interface\n\nThe non-generic interface for implementing deep cloning functionality.\n\n#### Methods\n\n| Name | Return Type | Description |\n|------|-------------|-------------|\n| `DeepClone()` | `object` | Creates a deep copy of the object, returned as an object that can be cast to the appropriate type |\n\n### `DeepCloneable\u003cTDerived\u003e` Abstract Class\n\nBase class that simplifies implementing deep cloning functionality and implements `IDeepCloneable` while providing strongly-typed cloning.\n\n#### Methods to Implement\n\n| Name | Return Type | Description |\n|------|-------------|-------------|\n| `CreateInstance()` | `TDerived` | Creates a new instance of the derived type |\n| `DeepClone(TDerived clone)` | `void` | Copies all properties and fields from the current instance to the clone |\n\n### Container Extension Methods\n\nExtension methods for deep cloning various container types.\n\n| Name | Container Type | Description |\n|------|---------------|-------------|\n| `DeepClone\u003cT\u003e` | `IEnumerable\u003cT?\u003e?` | Creates a deep clone of an enumerable collection |\n| `DeepClone\u003cTKey, TValue\u003e` | `IDictionary\u003cTKey, TValue?\u003e?` | Creates a deep clone of a dictionary |\n| `DeepClone\u003cTKey, TValue\u003e` | `IReadOnlyDictionary\u003cTKey, TValue?\u003e?` | Creates a deep clone of a read-only dictionary |\n| `DeepClone\u003cT\u003e` | `HashSet\u003cT?\u003e?` | Creates a deep clone of a hash set, preserving the comparer |\n| `DeepClone\u003cT\u003e` | `SortedSet\u003cT?\u003e?` | Creates a deep clone of a sorted set, preserving the comparer |\n| `DeepClone\u003cT\u003e` | `Stack\u003cT?\u003e?` | Creates a deep clone of a stack, preserving the element order |\n| `DeepClone\u003cT\u003e` | `ImmutableArray\u003cT\u003e` | Creates a deep clone of an immutable array |\n| `DeepClone\u003cT\u003e` | `ImmutableList\u003cT\u003e` | Creates a deep clone of an immutable list |\n| `DeepClone\u003cTKey, TValue\u003e` | `ImmutableDictionary\u003cTKey, TValue\u003e` | Creates a deep clone of an immutable dictionary |\n| `DeepClone\u003cTKey, TValue\u003e` | `ImmutableSortedDictionary\u003cTKey, TValue\u003e` | Creates a deep clone of an immutable sorted dictionary |\n| `DeepClone\u003cT\u003e` | `ImmutableHashSet\u003cT\u003e` | Creates a deep clone of an immutable hash set |\n| `DeepClone\u003cT\u003e` | `ImmutableSortedSet\u003cT\u003e` | Creates a deep clone of an immutable sorted set |\n| `DeepClone\u003cT\u003e` | `ImmutableStack\u003cT\u003e` | Creates a deep clone of an immutable stack |\n| `DeepClone\u003cT\u003e` | `ImmutableQueue\u003cT\u003e` | Creates a deep clone of an immutable queue |\n\n### DeepCloneFrom Extension Methods\n\nConvenience methods for cloning elements directly into an existing collection.\n\n| Name | Collection Types | Description |\n|------|-----------------|-------------|\n| `DeepCloneFrom\u003cT\u003e` | `ICollection\u003cT\u003e` | Clones all elements from source collection into the target collection |\n| `DeepCloneFrom\u003cTKey, TValue\u003e` | `IDictionary\u003cTKey, TValue\u003e` | Clones all key-value pairs from source dictionary into the target dictionary |\n| `DeepCloneFrom\u003cT\u003e` | `ISet\u003cT\u003e` | Clones all elements from source set into the target set |\n\nUsage Example:\n\n```csharp\n// For collections of IDeepCloneable objects\ntargetList.DeepCloneFrom(sourceList);\ntargetDictionary.DeepCloneFrom(sourceDictionary);\ntargetSet.DeepCloneFrom(sourceSet);\n\n// This is equivalent to (but more concise than):\nforeach (var item in sourceList)\n{\n    targetList.Add(item.DeepClone());\n}\n```\n\n## Importance of base.DeepClone in Inheritance\n\nWhen implementing `DeepClone` in derived classes, it's critical to call `base.DeepClone(clone)` first to ensure proper cloning of base class properties. This pattern creates a chain of calls that ensures all properties throughout the inheritance hierarchy are properly cloned.\n\n```csharp\nprotected override void DeepClone(MyDerivedClass clone)\n{\n    // ALWAYS call base.DeepClone first\n    base.DeepClone(clone);\n    \n    // Then clone derived class properties\n    clone.DerivedProperty1 = DerivedProperty1;\n    clone.DerivedProperty2 = DerivedProperty2?.DeepClone();\n    \n    // Use DeepCloneFrom for collections\n    clone.DerivedCollection.DeepCloneFrom(DerivedCollection);\n}\n```\n\nBenefits of this approach:\n- Each class is responsible only for cloning its own properties\n- Changes to base class properties only need to be updated in the base class\n- The entire object graph is properly cloned through the inheritance chain\n- Maintainable and less error-prone as the hierarchy evolves\n\n## Implementation Tips\n\nWhen implementing deep cloning, follow these guidelines:\n\n1. For value types and strings, a simple copy is sufficient\n2. For reference types, call their `DeepClone()` method (with null check)\n3. For collections, use the `DeepCloneFrom` extension methods\n4. Always call `base.DeepClone(clone)` first in derived classes\n5. For arrays, create a new array with the same dimensions\n6. Handle circular references to avoid infinite recursion\n7. Always check for null with `ArgumentNullException.ThrowIfNull` or null conditionals\n\n## Performance Considerations\n\nDeep cloning can be a resource-intensive operation, especially for complex object graphs. Here are some tips to optimize performance:\n\n1. **Lazy Clone When Possible**: If a property is expensive to clone and rarely modified, consider implementing lazy cloning.\n2. **Avoid Excessive Nesting**: Highly nested object structures with many references are more expensive to clone.\n3. **Consider Caching**: For frequently cloned immutable objects, consider caching the cloned instances.\n4. **Use ValueType Collections Wisely**: Collections of value types don't need full deep cloning.\n5. **Benchmark Critical Paths**: If deep cloning is on a performance-critical path, benchmark different approaches.\n\nExample of optimized cloning for a large object:\n\n```csharp\npublic class OptimizedObject : DeepCloneable\u003cOptimizedObject\u003e\n{\n    // Expensive to clone, but rarely modified\n    private ExpensiveResource? _resource;\n    private ExpensiveResource? _clonedResource;\n    \n    public ExpensiveResource? Resource \n    { \n        get =\u003e _resource;\n        set \n        {\n            _resource = value;\n            _clonedResource = null; // Invalidate cached clone\n        }\n    }\n\n    protected override OptimizedObject CreateInstance() =\u003e new OptimizedObject();\n    \n    protected override void DeepClone(OptimizedObject clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        \n        // Lazy clone the expensive resource only when needed\n        if (_resource != null)\n        {\n            // Cache the cloned resource to avoid redundant deep cloning\n            _clonedResource ??= _resource.DeepClone();\n            clone._resource = _clonedResource;\n        }\n    }\n}\n```\n\n## Troubleshooting Common Issues\n\n### 1. Objects Not Fully Independent After Cloning\n\n**Symptom**: Changes to a cloned object affect the original object.\n\n**Solution**: Ensure all reference-type properties are being properly deep cloned. Check for:\n- Missing DeepClone calls on reference-type properties\n- Not using DeepCloneFrom for collections\n- Forgetting to call base.DeepClone in derived classes\n\n### 2. Stack Overflow During Cloning\n\n**Symptom**: StackOverflowException occurs during deep cloning.\n\n**Solution**: This typically indicates a circular reference issue:\n- Implement circular reference detection in your DeepClone method\n- Use a Dictionary to track already-cloned objects\n\n```csharp\npublic class NodeWithCircularReferences : DeepCloneable\u003cNodeWithCircularReferences\u003e\n{\n    public string? Name { get; set; }\n    public NodeWithCircularReferences? Parent { get; set; }\n    public List\u003cNodeWithCircularReferences\u003e Children { get; set; } = new();\n    \n    // Dictionary for tracking already cloned instances across the object graph\n    private static readonly ThreadLocal\u003cDictionary\u003cNodeWithCircularReferences, NodeWithCircularReferences\u003e\u003e CloneTracker = \n        new(() =\u003e new Dictionary\u003cNodeWithCircularReferences, NodeWithCircularReferences\u003e());\n    \n    protected override NodeWithCircularReferences CreateInstance() =\u003e new();\n    \n    protected override void DeepClone(NodeWithCircularReferences clone)\n    {\n        ArgumentNullException.ThrowIfNull(clone);\n        base.DeepClone(clone);\n        \n        // Ensure we have a clone tracker\n        var cloneTracker = CloneTracker.Value!;\n        \n        // Track this instance and its clone\n        cloneTracker[this] = clone;\n        \n        // Set simple properties\n        clone.Name = Name;\n        \n        // Handle potential circular reference with Parent\n        if (Parent != null)\n        {\n            // Check if parent was already cloned in this cloning operation\n            if (cloneTracker.TryGetValue(Parent, out var parentClone))\n                clone.Parent = parentClone;\n            else\n                clone.Parent = Parent.DeepClone(); // This will add to the tracker\n        }\n        \n        // Handle collection of children that might have circular references\n        foreach (var child in Children)\n        {\n            // Check if child was already cloned in this operation\n            if (cloneTracker.TryGetValue(child, out var childClone))\n                clone.Children.Add(childClone);\n            else\n                clone.Children.Add(child.DeepClone()); // This will add to the tracker\n        }\n    }\n}\n```\n\n### 3. Type Mismatch in Polymorphic Collections\n\n**Symptom**: After cloning a polymorphic collection, objects don't maintain their derived types.\n\n**Solution**: Ensure you're implementing `IDeepCloneable` correctly for polymorphic use:\n- For base classes inheriting from DeepCloneable\u003cTDerived\u003e, the non-generic interface is already implemented\n- Override CreateInstance() to return the correct concrete type\n- Use proper type checking and casting in DeepClone methods if needed\n- Consider using interface hierarchies (like IAnimal, IMammal, IDog) for type-safe polymorphism\n\n### 4. Immutable Collection Cloning Issues\n\n**Symptom**: Immutable collections don't clone properly or reference equality is maintained.\n\n**Solution**: Use the appropriate extension methods specific to immutable collections:\n- For value-type immutable collections, direct assignment is usually sufficient\n- For reference-type immutable collections, use the DeepClone extension methods\n- Never manually iterate and rebuild immutable collections\n\n## Contributing\n\nContributions are welcome! Here's how you can help:\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\nPlease make sure to update tests as appropriate and adhere to the existing coding style.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.\n\n## Acknowledgments\n\nThis library is inspired by the [ppy/osu!](https://github.com/ppy/osu) project's cloning utilities.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fktsu-dev%2Fdeepclone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fktsu-dev%2Fdeepclone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fktsu-dev%2Fdeepclone/lists"}