DeepCopy.Expression
1.6.0
dotnet add package DeepCopy.Expression --version 1.6.0
NuGet\Install-Package DeepCopy.Expression -Version 1.6.0
<PackageReference Include="DeepCopy.Expression" Version="1.6.0" />
<PackageVersion Include="DeepCopy.Expression" Version="1.6.0" />
<PackageReference Include="DeepCopy.Expression" />
paket add DeepCopy.Expression --version 1.6.0
#r "nuget: DeepCopy.Expression, 1.6.0"
#:package DeepCopy.Expression@1.6.0
#addin nuget:?package=DeepCopy.Expression&version=1.6.0
#tool nuget:?package=DeepCopy.Expression&version=1.6.0
DeepCopy.Expression
DeepCopy.Expression is a high-performance deep copy library for .NET.
It generates clone logic with expression trees and cashes compiled delegates for repreated use.
A deep copy duplicates not only the object itself, but also the objects it references. An Expression Tree is a data structure that represents code as a tree of expressions.
Features
- Deep copy for classes, structs, nullable structs, and anonymous types
- Array clone APIs for
T[],T[,],T[,,],T[,,,],T[,,,,]and non-genericArray - Supports deep cloning of polymorphic object hierarchies, including abstract classes and interfaces
- Handles circular references and self-referencing object graphs
- Supports cloning deeply nested object graphs such as
LinkedList<T>. - Optional reference-preserving mode (
preserveObjectReferencesparameter) for shared object graphs - Member-level copy control with
[Cloneable], [CopyMember]attributes andCopyPolicyparameter. - Custom clone logic registration for each type
- Warm-up and cache lifecycle APIs:
Compile<T>andCleanup<T>methods
Installation
To install the library, you can use the following command in the Package Manager Console
PM > Install-Package DeepCopy.Expression
Supported Target Frameworks
net10.0netstandard2.0
Quick Start
To create a deep copy of an object, call the ObjectCloner.Clone method:
var source = new User
{
Id = 1,
Name = "John Doe",
Tags = new List<string> { "admin", "reviewer" }
};
var cloned = ObjectCloner.Clone(source);
Anonymous types are also supported:
var source = new
{
Id = 1,
Name = "John Doe",
Tags = ["admin", "reviewer"]
};
var cloned = ObjectCloner.Clone(source);
Preserving Shared References
By default, objects are deep-cloned without preserving shared references to maximize performance.
If the object graph contains shared nodes and reference identity must be preserved, pass true:
var cloned = ObjectCloner.Clone(source, preserveObjectReferences: true);
Attribute-Based Member Control
Default behavior (without [Cloneable]:
- All instance fields are copied, including private fields.
- Event backing fields are excluded
Opt-in behavior (with [Cloneable]):
- Only members marked with
[CopyMember]are copied - A
CopyPolicycan be specified for each member
[Cloneable]
public sealed class Settings
{
[CopyMember]
private readonly string _id = Guid.NewGuid().ToString();
[CopyMember(CopyPolicy.DeepCopy)]
public List<string> Values { get; set; } = new ();
[CopyMember(CopyPolicy.Assign)]
public IServiceProvider ServiceProvider { get; set; } = default!;
}
Copy Policy
The following copy policies are available:
Default: Uses the default behavior for the member type. Value types are assigned, reference types are deep-copied, arrays are cloned, and delegates are assigned.DeepCopy: Performs a deep copy of the member regardless of its type.ShallowCopy: Performs a shallow copy of the member regardless of its type. A shallow copy duplicates only the object itself and not the objects it references.Assign: Copies the member as-is regardless of its type. For reference types, no new instance is created and the original reference is shared.
| ValueType | Class /<br>Struct (contains references) | Array (Value Type) | Array (Class) | Delegate | |
|---|---|---|---|---|---|
| Default | Assign | DeepCopy | Clone | DeepCopy | Assign |
| DeepCopy | Assign | DeepCopy | DeepCopy | DeepCopy | Assign |
| ShallowCopy | Assign | MemberwiseClone | Clone | Clone | Assign |
| Assign | Assign | Assign | Assign | Assign | Assign |
Custom Clone Registration
Starting with version 1.5.0, custom clone logic can be registered for specific types using the ObjectCloner.RegisterCustomClone method.
The following example ensures that cloned object recieves a new unique ID:
ObjectCloner.RegisterCustomClone(
typeof(MyCustomizableObject),
(source, destination, context) =>
{
var fields = CustomCloneHelper.BuildCloneFieldsExpression(
source.Type, source, destination, context, "_id");
return Expression.Block(
fields,
CustomCloneHelper.BuildFieldAssignment(
destination, "_id", Guid.NewGuid())
);
});
Performance
This is a benchmark of TestObject's deep clone. The performance of the library is comparable to the code that is specially implemented for deep copying. The library uses caching to avoid generating expression trees every time. The first time you clone an object, it may take longer than subsequent times.
| Method | Mean | Error | StdDev | Ratio | Gen 0 |
|---|---|---|---|---|---|
| CloneWithImprementation | 41.77 us | 1.4089 us | 4.0425 us | 1.00 | 30.0293 |
| CloneWithSerialization | 698.42 us | 5.5453 us | 4.9158 us | 15.57 | 179.6875 |
| CloneWithExpressionFirstTimeOnly | 4,242.48 us | 84.4623 us | 97.2669 us | 97.07 | 179.6875 |
| CloneWithExpression | 42.37 us | 0.5604 us | 0.5242 us | 0.95 | 27.8931 |
Limitations
The library has some limitations:
- Delegates are not copied and are shared between the source and cloned objects.
CopyTois disabled for immutable collections such asImmutableList<T>,ImmutableStack<T>,ImmutableQueue<T>, andImmutableHashSet<T>.ImmutableHashSet<T>andImmutableSortedSet<T>cannot be cloned correctly when they contain self-references.- To prevent stack overflows, members deeper than
DeepCopyOptions.MaxRecursionDepthare processed interatively, except for types specified inDeepCopyOptions.NonCopyableGenericTypes, which are always processed recursively.
License
This library is under the MIT License.
| 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 is compatible. 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 is compatible. 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.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on DeepCopy.Expression:
| Package | Downloads |
|---|---|
|
Saritasa.NetForge
The NetForge is a library that provides a user-friendly and intuitive user interface for performing CRUD operations on your database entities within your .NET applications. |
|
|
FastCloner.Benchmark
Package Description |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on DeepCopy.Expression:
| Repository | Stars |
|---|---|
|
lofcz/FastCloner
The fastest deep cloning library for .NET – zero-config, works out of the box.
|
| Version | Downloads | Last Updated |
|---|---|---|
| 1.6.0 | 71 | 6/21/2026 |
| 1.5.0 | 18,601 | 3/4/2025 |
| 1.5.0-alpha.1 | 164 | 2/13/2025 |
| 1.4.2 | 1,449 | 11/10/2024 |
| 1.4.1 | 11,777 | 2/24/2024 |
| 1.4.0 | 6,371 | 8/19/2023 |
| 1.3.0 | 40,591 | 4/4/2021 |
| 1.2.1 | 1,153 | 5/14/2019 |
| 1.2.0 | 771 | 5/2/2019 |
| 1.1.1 | 810 | 4/29/2019 |
| 1.1.0 | 792 | 3/21/2019 |
| 1.0.2 | 822 | 3/3/2019 |
| 1.0.1 | 857 | 2/10/2019 |
| 1.0.0 | 1,185 | 2/8/2019 |