IDeepCloneable 0.0.20
See the version list below for details.
dotnet add package IDeepCloneable --version 0.0.20
NuGet\Install-Package IDeepCloneable -Version 0.0.20
<PackageReference Include="IDeepCloneable" Version="0.0.20" />
<PackageVersion Include="IDeepCloneable" Version="0.0.20" />
<PackageReference Include="IDeepCloneable" />
paket add IDeepCloneable --version 0.0.20
#r "nuget: IDeepCloneable, 0.0.20"
#:package IDeepCloneable@0.0.20
#addin nuget:?package=IDeepCloneable&version=0.0.20
#tool nuget:?package=IDeepCloneable&version=0.0.20
IDeepCloneable
Automatic implementation of the IDeepCloneable<T> interface via source generators. Suitable for both library authors and users.
Overview
Provides automatic generation of the DeepClone() method and IDeepCloneable<T> implementation for partial types marked with [DeepCloneable].
Quick Start (for users)
Install the NuGet package IDeepCloneable to your project.
dotnet add package IDeepCloneable
Then mark a partial type with the [DeepCloneable] attribute.
[DeepCloneable] // <- add this attribute
public partial class Person // <- make it partial
{
public string Name { get; set; }
public int Age { get; set; }
}
That's it! The DeepClone() method will be automatically generated and the generated partial type will implement IDeepCloneable<Person>.
// generated code (sample)
partial class Person : IDeepCloneable<Person>
{
public Person DeepClone()
{
return new Person
{
Name = this.Name,
Age = this.Age,
};
}
}
And you can use it like this:
var person1 = new Person { Name = "Alice", Age = 30 };
var person2 = person1.DeepClone();
Usage for library authors
Library authors can use the IDeepCloneable<T> interface to perform DeepClone() without reflection.
First, install the NuGet package IDeepCloneable to your project.
dotnet add package IDeepCloneable
Then, you can check if a type implements IDeepCloneable<T> and call the DeepClone() method accordingly.
public void RegisterCloneMethod<T>()
{
Func<T, T> cloneFunc = null;
bool isDeepCloneable = typeof(IDeepCloneable<T>).IsAssignableFrom(typeof(T));
if(isDeepCloneable) {
cloneFunc = value => ((IDeepCloneable<T>)value).DeepClone();
}
else {
// fallback implementation
}
}
// or using generic constraints
public void RegisterCloneMethod<T>() where T : IDeepCloneable<T>
{
Func<T, T> cloneFunc = value => value.DeepClone();
}
This completes the setup. Library users do not need to introduce IDeepCloneable; they only need to apply [DeepCloneable].
// user side
[DeepCloneable]
public partial class MyModel { /* ... */ }
// call library method
library.RegisterCloneMethod<MyModel>();
Benefits
While there are many similar libraries available, this library's key feature is that it generates the DeepClone() method as an implementation of the IDeepCloneable<T> interface.
By doing this:
- Library authors can use
DeepClone()without reflection (NativeAOT friendly) - Users are relieved of the burden of manual implementation
Performance
Performance is a concern, right? In benchmarks for medium-sized models, it shows comparable results to major libraries.
| Method | Mean | Ratio | Gen0 | Gen1 | Allocated |
|---|---|---|---|---|---|
| IDeepCloneable | 912.7 ns | 1.00 | 0.2890 | 0.0048 | 4.73 KB |
| Mapperly | 996.6 ns | 1.09 | 0.2880 | 0.0038 | 4.73 KB |
| FastCloner_SourceGen | 1,147.7 ns | 1.26 | 0.2880 | 0.0038 | 4.73 KB |
| AutoMapper | 3,139.2 ns | 3.44 | 0.3433 | 0.0038 | 5.65 KB |
| FastCloner_Reflection | 8,772.5 ns | 9.61 | 0.8392 | 0.0153 | 13.79 KB |
| SystemTextJson_Reflection | 31,857.2 ns | 34.90 | 1.2207 | - | 20.59 KB |
Detailed results can be found in benchmark/results and Benchmark source code.
Customize
As you can see from the generated code, you can simply implement the IDeepCloneable<T>.DeepClone() method yourself.
public class Person : IDeepCloneable<Person>
{
public string Name { get; set; }
public int Age { get; set; }
public Person DeepClone()
{
// your custom implementation
}
}
Library Structure
This consists of two libraries.
IDeepCloneable
This is the library that defines the IDeepCloneable<T> interface and the [DeepCloneable] marker attribute.
To allow users of third-party libraries to use it without worrying about IDeepCloneable, it is defined directly under the global namespace.
public sealed class DeepCloneableAttribute : Attribute;
public interface IDeepCloneable<T>
{
T DeepClone();
}
Additionally, it will automatically reference the IDeepCloneable.Generator.
IDeepCloneable.Generator
This is the source generator library that automatically generates the IDeepCloneable<T>.DeepClone() method.
There is no need to directly reference this library.
FAQ
What is DeepClone?
DeepClone (also commonly referred to as DeepCopy) refers to the operation of creating a complete copy of an object.
For example, if you simply assign an object, reference-type properties are not copied, and both variables will point to the same instance.
var person1 = new Person
{
Name = "Alice",
Address = new Address { City = "Wonderland" }
};
var person2 = person1; // shallow copy
person2.Address.City = "New City";
// person1.Address.City is now "New City"
Additionally, in the following example, the Address property is a shallow copy, which is insufficient.
var person3 = new Person
{
Name = person1.Name,
Address = person1.Address // shallow copy
};
person3.Address.City = "Another City";
// person1.Address.City is now "Another City"
To avoid this, you would need to manually copy everything.
var person4 = new Person
{
Name = person1.Name,
Address = new Address { City = person1.Address.City }
};
person4.Address.City = "Different City";
// person1.Address.City remains unchanged
Writing this every time is tedious. Instead, you can use the DeepClone() method.
public class Person
{
public string Name { get; set; }
public Address Address { get; set; }
public Person DeepClone()
{
return new Person
{
Name = this.Name,
Address = new Address
{
City = this.Address.City
}
};
}
}
var person5 = person1.DeepClone();
person5.Address.City = "Cloned City";
// person1.Address.City remains unchanged
While this works, it is still a bit cumbersome. With this library, you can automatically generate the implementation of the DeepClone() method.
[DeepCloneable] // <- add this attribute
public partial class Person // <- make it partial
{
public string Name { get; set; }
public Address Address { get; set; }
}
var person6 = person1.DeepClone();
person6.Address.City = "Auto Cloned City";
// person1.Address.City remains unchanged
Why not use ICloneable?
This library implements its own IDeepCloneable<T> interface instead of the standard System.ICloneable for the following reasons:
- The behavior of
ICloneable.Clone()is ambiguous—it is unclear whether it performs a shallow or deep copy. ICloneable.Clone()is non-generic, so you must cast the return value.
For these reasons, even as early as 2004, the use of ICloneable was not recommended. Reference
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on IDeepCloneable:
| Repository | Stars |
|---|---|
|
lofcz/FastCloner
The fastest deep cloning library for .NET – zero-config, works out of the box.
|
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.4 | 541 | 2/3/2026 |
| 0.1.3 | 110 | 2/2/2026 |
| 0.1.2 | 97 | 2/2/2026 |
| 0.1.1 | 113 | 2/1/2026 |
| 0.1.0 | 99 | 1/30/2026 |
| 0.0.27 | 125 | 1/12/2026 |
| 0.0.26 | 99 | 1/12/2026 |
| 0.0.25 | 100 | 1/12/2026 |
| 0.0.24 | 109 | 1/12/2026 |
| 0.0.23 | 102 | 1/12/2026 |
| 0.0.22 | 111 | 1/12/2026 |
| 0.0.21 | 106 | 1/11/2026 |
| 0.0.20 | 104 | 1/9/2026 |
| 0.0.10 | 105 | 1/6/2026 |
| 0.0.5 | 481 | 1/4/2026 |
| 0.0.4 | 112 | 1/2/2026 |
| 0.0.3 | 111 | 1/1/2026 |
| 0.0.2 | 466 | 12/31/2025 |
| 0.0.1 | 102 | 12/31/2025 |