FastCloner 3.5.2
Prefix Reserveddotnet add package FastCloner --version 3.5.2
NuGet\Install-Package FastCloner -Version 3.5.2
<PackageReference Include="FastCloner" Version="3.5.2" />
<PackageVersion Include="FastCloner" Version="3.5.2" />
<PackageReference Include="FastCloner" />
paket add FastCloner --version 3.5.2
#r "nuget: FastCloner, 3.5.2"
#:package FastCloner@3.5.2
#addin nuget:?package=FastCloner&version=3.5.2
#tool nuget:?package=FastCloner&version=3.5.2
<div align="center">
<img width="512" alt="FastCloner" src="https://github.com/user-attachments/assets/9b6b82a3-892a-4607-9c57-6580ca856a37" />
FastCloner
The fastest and most reliable .NET deep cloning library.
FastCloner is a zero-dependency deep cloning library for .NET, from <code>.NET 4.6</code> to <code>.NET 10+</code>. It combines source generation with optimized reflection fallback, so deep cloning just works.
</div>
✨ Features
- The Fastest - Benchmarked to beat all other libraries with third-party independent benchmarks verifying the performance. 300x speed-up vs
Newtonsoft.Jsonand 160x vsSystem.Text.Json - The Most Correct - Built for the cases clone libraries get wrong: polymorphism, circular/shared references, readonly and immutable members, deep graphs, delegates, events, collections... Backed by 800+ tests, with documented limitations
- Hybrid AOT - Uses generated clone code wherever possible, with targeted fallback to the runtime engine only where safety or correctness requires it
- Automatic type discovery - The generator follows usages of generic and abstract types and emits concrete clone paths automatically
- Embeddable - No dependencies outside the standard library. Source generator and reflection parts can be installed independently
- Precise control - Override clone behavior per type or member with
Clone,Reference,Shallow, orIgnore, at compile time or runtime - Selective tracking - FastCloner avoids identity and cycle-tracking overhead by default, but enables it when graph shape or
[FastClonerPreserveIdentity]requires it - Easy Integration -
FastDeepClone()for AOT cloning,DeepClone()for reflection cloning. FastCloner respects standard .NET attributes like[NonSerialized], so you can adopt it without depending on library-specific annotations - Production Ready - Used by projects like Foundatio, Jobbr, TarkovSP, SnapX, and WinPaletter, with over 300K downloads on NuGet
Getting Started
Install the package via NuGet:
dotnet add package FastCloner # Reflection
dotnet add package FastCloner.SourceGenerator # AOT
Clone via Reflection
using FastCloner.Code;
var clone = FastCloner.FastCloner.DeepClone(new { Hello = "world", MyList = new List<int> { 1 } });
For convenience, add the following method to your project. We intentionally don't ship this extension to make switching from/to FastCloner easier:
[return: NotNullIfNotNull(nameof(obj))]
public static T? DeepClone<T>(this T? obj)
{
return FastCloner.FastCloner.DeepClone(obj);
}
Clone via Source Generator
[FastClonerClonable]
public class GenericClass<T>
{
public T Value { get; set; }
}
public class MyClass
{
public string StrVal { get; set; }
}
// [FastClonerClonable] is only required on types where you call .FastDeepClone()
var original = new GenericClass<List<MyClass>> { Value = new List<MyClass> { new MyClass { StrVal = "hello world" } } };
var clone = original.FastDeepClone();
Advanced Usage
Customizing Clone Behavior
FastCloner supports behavior attributes that control how types and members are cloned:
| Behavior | Effect |
|---|---|
Clone |
Deep recursive copy |
Reference |
Return original instance unchanged |
Shallow |
MemberwiseClone without recursion |
Ignore |
Return default |
Compile-time (Attributes)
Apply attributes to types or members. Member-level attributes override type-level:
[FastClonerReference] // Type-level: all usages preserve reference
public class SharedService { }
public class MyClass
{
public SharedService Svc { get; set; } // Uses type-level → Reference
[FastClonerBehavior(CloneBehavior.Clone)] // Member-level override → Clone
public SharedService ClonedSvc { get; set; }
[FastClonerIgnore] // → null/default
public CancellationToken Token { get; set; }
[FastClonerShallow] // → Reference copied directly
public ParentNode Parent { get; set; }
}
Shorthand attributes: [FastClonerIgnore], [FastClonerShallow], [FastClonerReference]
Explicit: [FastClonerBehavior(CloneBehavior.X)]
Runtime (Reflection only)
Configure type behavior dynamically. Runtime settings are checked before attributes:
FastCloner.FastCloner.SetTypeBehavior<MySingleton>(CloneBehavior.Reference);
FastCloner.FastCloner.ClearTypeBehavior<MySingleton>(); // Reset one
FastCloner.FastCloner.ClearAllTypeBehaviors(); // Reset all
Note: Changing runtime behavior invalidates the cache. Try to configure once at startup, or use compile-time attributes when possible.
Precedence (highest to lowest)
- Runtime
SetTypeBehavior<T>() - Member-level attribute
- Type-level attribute on member's type
- Default behavior
Cache Management
FastCloner.FastCloner.ClearCache(); // Free memory from reflection cache
Generic Classes and Abstract Types
The source generator automatically discovers which concrete types your generic classes and abstract hierarchies are used with:
Generic types - The generator scans your codebase for usages like MyClass<int> or MyClass<Customer> and generates specialized cloning code:
[FastClonerClonable]
public class Container<T>
{
public T Value { get; set; }
}
// Source generator finds this usage and generates cloning code for Container<int>
var container = new Container<int> { Value = 42 };
var clone = container.FastDeepClone();
Abstract classes - The generator automatically finds all concrete derived types in your codebase:
[FastClonerClonable]
public abstract class Animal
{
public string Name { get; set; }
}
public class Dog : Animal
{
public string Breed { get; set; }
}
public class Cat : Animal
{
public bool IsIndoor { get; set; }
}
// Cloning via the abstract type works - the generator discovered Dog and Cat
Animal pet = new Dog { Name = "Buddy", Breed = "Labrador" };
Animal clone = pet.FastDeepClone(); // Returns a cloned Dog
Explicitly Including Types
When a type is only used dynamically (not visible at compile time), use [FastClonerInclude] to ensure the generator creates cloning code for it:
[FastClonerClonable]
[FastClonerInclude(typeof(Customer), typeof(Order))] // Include types used dynamically
public class Wrapper<T>
{
public T Value { get; set; }
}
For abstract classes, you can also use [FastClonerInclude] to add derived types that aren't in your codebase (e.g., from external assemblies):
[FastClonerClonable]
[FastClonerInclude(typeof(ExternalPlugin))] // Add external derived types
public abstract class Plugin
{
public string Name { get; set; }
}
Custom Cloning Context
For advanced scenarios, create a custom cloning context to explicitly register types you want to clone. This is useful when you need a centralized cloning entry point or want to clone types from external assemblies:
public class Customer
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string City { get; set; }
}
// Create a context and register types to clone
[FastClonerRegister(typeof(Customer), typeof(Address))]
public partial class MyCloningContext : FastClonerContext { }
Using the context:
MyCloningContext ctx = new MyCloningContext();
// Clone with compile-time type safety
Customer clone = ctx.Clone(original);
// Check if a type is handled by this context
bool handled = ctx.IsHandled(typeof(Customer)); // true
// Try to clone (returns false for unregistered types)
if (ctx.TryClone(obj, out var cloned))
{
// Successfully cloned
}
Nullability Trust
The generator can be instructed to fully trust nullability annotations. When [FastClonerTrustNullability] attribute is applied, FastCloner will skip null checks for non-nullable reference types (e.g., string vs string?), assuming the contract is valid.
[FastClonerClonable]
[FastClonerTrustNullability] // Skip null checks for non-nullable members
public class HighPerformanceDto
{
public string Id { get; set; } // No null check generated
public string? Details { get; set; } // Null check still generated
}
This eliminates branching and improves performance slightly. If a non-nullable property is actually null at runtime, this may result in a NullReferenceException in the generated code.
Safe Handles
When you have a struct that acts as a handle to internal state or a singleton (where identity matters), use [FastClonerSafeHandle]. This tells FastCloner to shallow-copy the readonly fields instead of deep-cloning them, preserving the original internal references.
[FastClonerSafeHandle]
public struct MyHandle
{
private readonly object _internalState; // Preserved (shared), not deep cloned
public int Value; // Cloned normally
}
This is the default behavior for system types like System.Net.Http.Headers.HeaderDescriptor to prevent breaking internal framework logic. Use this attribute if your custom structs behave similarly.
Identity Preservation
By default, FastCloner prioritizes performance by not tracking object identity during cloning. This means if the same object instance appears multiple times in your graph, each reference becomes a separate clone.
For scenarios where you need to preserve object identity (e.g., shared references should remain shared in the clone), use [FastClonerPreserveIdentity]:
[FastClonerClonable]
[FastClonerPreserveIdentity] // Enable identity tracking for this type
public class Document
{
public User Author { get; set; }
public User LastEditor { get; set; } // May reference the same User as Author
}
var doc = new Document { Author = user, LastEditor = user };
var clone = doc.FastDeepClone();
// clone.Author == clone.LastEditor (same cloned instance)
The attribute can be applied at type level or member level:
[FastClonerClonable]
public class Container
{
// Only this member tracks identity
[FastClonerPreserveIdentity]
public List<Node> Nodes { get; set; }
// This member clones without identity tracking (faster)
public List<Item> Items { get; set; }
}
You can also explicitly disable identity preservation for a member when the type has it enabled:
[FastClonerClonable]
[FastClonerPreserveIdentity]
public class Graph
{
public Node Root { get; set; }
[FastClonerPreserveIdentity(false)] // Opt out for this member
public List<string> Labels { get; set; }
}
Note: Identity preservation adds overhead for tracking seen objects. Circular references are always detected regardless of this setting.
Limitations
- Cloning unmanaged resources, such as
IntPtrs may result in side-effects, as there is no metadata for the length of buffers such pointers often point to. ReadOnlyandImmutablecollections are tested to behave well if they follow basic conventions.- With reflection, cloning deeply nested objects switches from recursion to iterative approach on the fly. The threshold for this can be configured by changing
FastCloner.MaxRecursionDepth, iterative approach is marginally slower.
Performance
FastCloner is the fastest deep cloning library across both reflection-based and AOT workloads. It was benchmarked against every library capable of cloning objects I've been able to find:
BenchmarkDotNet v0.15.8, Windows 11 (10.0.26220.7271)
Intel Core i7-8700 CPU 3.20GHz (Max: 3.19GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.100
| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Rank | Gen0 | Gen1 | Allocated | Alloc Ratio |
|------------------- |------------:|-----------:|-----------:|------------:|-------:|--------:|-----:|-------:|-------:|----------:|------------:|
| FastCloner | 10.25 ns | 0.219 ns | 0.183 ns | 10.24 ns | 1.00 | 0.02 | 1 | 0.0115 | - | 72 B | 1.00 |
| DeepCopier | 23.37 ns | 0.448 ns | 0.582 ns | 23.29 ns | 2.28 | 0.07 | 2 | 0.0115 | - | 72 B | 1.00 |
| DeepCopy | 40.56 ns | 3.589 ns | 10.583 ns | 43.56 ns | 3.96 | 1.03 | 3 | 0.0115 | - | 72 B | 1.00 |
| DeepCopyExpression | 126.05 ns | 3.355 ns | 9.892 ns | 129.32 ns | 12.30 | 0.98 | 4 | 0.0356 | - | 224 B | 3.11 |
| AutoMapper | 135.07 ns | 6.097 ns | 17.976 ns | 143.16 ns | 13.18 | 1.76 | 5 | 0.0114 | - | 72 B | 1.00 |
| DeepCloner | 261.42 ns | 14.113 ns | 41.614 ns | 282.99 ns | 25.51 | 4.06 | 6 | 0.0367 | - | 232 B | 3.22 |
| ObjectCloner | 336.89 ns | 14.249 ns | 42.012 ns | 355.28 ns | 32.87 | 4.12 | 7 | 0.0534 | - | 336 B | 4.67 |
| MessagePack | 499.71 ns | 20.831 ns | 61.420 ns | 524.63 ns | 48.75 | 6.02 | 8 | 0.0315 | - | 200 B | 2.78 |
| ProtobufNet | 898.60 ns | 34.925 ns | 102.978 ns | 934.13 ns | 87.67 | 10.11 | 9 | 0.0782 | - | 496 B | 6.89 |
| NClone | 904.75 ns | 33.559 ns | 98.949 ns | 919.05 ns | 88.27 | 9.73 | 9 | 0.1488 | - | 936 B | 13.00 |
| SystemTextJson | 1,687.39 ns | 70.341 ns | 201.821 ns | 1,766.14 ns | 164.63 | 19.79 | 10 | 0.1755 | - | 1120 B | 15.56 |
| NewtonsoftJson | 3,147.66 ns | 109.097 ns | 321.676 ns | 3,269.96 ns | 307.10 | 31.67 | 11 | 0.7286 | 0.0038 | 4592 B | 63.78 |
| FastDeepCloner | 3,970.90 ns | 155.503 ns | 458.505 ns | 4,128.09 ns | 387.41 | 45.01 | 12 | 0.2060 | - | 1304 B | 18.11 |
| AnyCloneBenchmark | 5,102.40 ns | 239.089 ns | 704.959 ns | 5,370.93 ns | 497.81 | 68.98 | 13 | 0.9003 | - | 5656 B | 78.56 |
You can run the benchmark locally to verify the results.
Build Times & IDE Performance
The source generator is designed to work with Roslyn's incremental model. It uses ForAttributeWithMetadataName, turns Roslyn symbols into stable TypeModel / MemberModel records early, and keeps ISymbol, syntax nodes, and Compilation out of the output pipeline.
- Incremental pipeline - Type analysis happens during the transform step, so codegen re-runs only when decorated types or relevant usage data changes.
- Stable models -
TypeModelandMemberModelhold precomputed data instead of Roslyn symbols, which keeps incremental caching effective across edits. - No
CompilationProviderin output - The output pipeline intentionally avoids it to reduce broad invalidation and unnecessary regeneration. - Deterministic collection equality -
EquatableArrayis used so generator model collections compare cleanly in the incremental pipeline. - Inlining of one-off helpers - Helpers used once are inlined to keep generated clone paths direct.
Internalization
For consumers who wish to embed FastCloner directly without adding a dependency, use the internalization builder project.
Example command:
dotnet run --project src/FastCloner.Internalization.Builder/FastCloner.Internalization.Builder.csproj -- \
--root-namespace MyLibrary.FastCloner \
--output ../MyLibrary/FastCloner \
--preprocessor "MODERN=true;" \
--fqn all \
--visibility internal \
--public-api none \
--runtime-only true \
--self-check
CLI options:
--root-namespace <ns>: RewritesFastClonernamespaces to your target root namespace.--preprocessor <SYMBOL=VALUE;...>: Per-symbol preprocessor transformation input.VALUE=true|falseis recognized as boolean and enables full condition resolution/removal where possible.- any other value is used as direct replacement in
#ifexpressions (e.g.,SOMETHING=random_text). - This lets the builder resolve
#ifbranches ahead of time and emit target-specific code.
--fqn <prefix1|prefix2|...>: Fully qualifies matching external metadata types in generated code.- Use
allto qualify all external metadata types. - Use prefixes such as
System|System.Collectionsto limit qualification to selected namespaces. - This is useful when embedding FastCloner into a project that already defines colliding namespaces or type names.
- Use
--implicit-usings <ns1;ns2;...>: Namespaces the target project already imports implicitly.
Generated global usings for these namespaces are omitted.
Default is empty, so generated code carries explicit usings.--visibility <public|internal>: Top-level visibility rewrite policy.--public-api <none|fastcloner|extensions|behaviors|all>: Keeps selected public surface when--visibility internalis used.--runtime-only <true|false>: Includes only runtime clone engine files.--dry-run: Prints planned output files and transform stats without writing.--self-check: Compiles generated source tree and reports compile errors.
Contributing
If you are looking to add new functionality, please open an issue first to verify your intent is aligned with the scope of the project. The library is covered by over 800 tests, please run them against your work before proposing changes. Tests run in parallel to verify thread-safety of the library (with targeted exceptions). Run dotnet test from the cloned repo root. We also run benchmark regression analysis on every pull request to next; if a change causes a measurable performance regression, the PR should clearly justify that trade-off. When reporting issues, providing a minimal reproduction we can plug in as a new test greatly reduces turnaround time. We use TUnit for testing.
Each PR gets an updated benchmark report comment from github-actions, so you can spot regressions early and iterate before merge.
<details> <summary>Example benchmark report</summary>
| Status | Benchmark | Delta Time | Delta Alloc |
|---|---|---|---|
| 🟢 | DynamicWithArray | -15% faster | ~same |
| ⚪ | DynamicWithDictionary | +5% slower | ~same |
| ⚪ | DynamicWithNestedObject | ~same | ~same |
| ⚪ | FileSpec | -4% faster | ~same |
| 🟢 | LargeEventDocument_10MB | -7% faster | ~same |
| ⚪ | LargeLogBatch_10MB | ~same | ~same |
| ⚪ | MediumNestedObject | ~same | ~same |
| ⚪ | ObjectDictionary_50 | ~same | ~same |
| ⚪ | ObjectList_100 | -2% faster | ~same |
| 🟢 | SmallObject | -6% faster | ~same |
| ⚪ | SmallObjectWithCollections | -2% faster | ~same |
| ⚪ | StringArray_1000 | ~same | ~same |
</details>
<details> <summary>Tests Troubleshooting</summary>
Rider: automatic tests discovery
- Temporarily disable VSTest adapters support (
Build, Execution, Deployment > Unit Testing > VSTest) - Enable Testing Platform support (
Build, Execution, Deployment > Unit Testing > Testing Platform) - Re-enable VSTest adapters support
- Rebuild / refresh the test explorer
</details>
License
This library is licensed 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 | net46 is compatible. 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. |
-
.NETFramework 4.6
- No dependencies.
-
.NETStandard 2.0
- No dependencies.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (8)
Showing the top 5 NuGet packages that depend on FastCloner:
| Package | Downloads |
|---|---|
|
Jobbr.Server
Scaffolding that manages the Jobbr server and uses other compomenents depending on the registration |
|
|
BXJG.Common
Package Description |
|
|
SPTarkov.Server.Core
Core library for the Single Player Tarkov server. |
|
|
FastCloner.Contrib
Extends FastCloner with support for certain special types. |
|
|
Unleasharp.DB.Base
A multi-purpose database query building library. Generic abstractions. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.5.2 | 0 | 3/10/2026 |
| 3.5.1 | 301 | 3/6/2026 |
| 3.5.0 | 39 | 3/6/2026 |
| 3.4.7 | 2,792 | 2/26/2026 |
| 3.4.6 | 1,171 | 2/25/2026 |
| 3.4.5 | 2,467 | 2/23/2026 |
| 3.4.4 | 16,906 | 1/27/2026 |
| 3.4.3 | 6,953 | 1/19/2026 |
| 3.4.2 | 806 | 1/17/2026 |
| 3.4.1 | 129 | 1/16/2026 |
| 3.4.0 | 8,367 | 1/8/2026 |
| 3.3.23 | 2,999 | 1/5/2026 |
| 3.3.22 | 1,017 | 12/30/2025 |
| 3.3.21 | 117 | 12/30/2025 |
| 3.3.20 | 12,035 | 12/10/2025 |
| 3.3.19 | 2,696 | 12/5/2025 |
| 3.3.18 | 6,022 | 12/2/2025 |
| 3.3.17 | 14,183 | 11/15/2025 |
| 3.3.16 | 54,087 | 10/5/2025 |
| 3.3.15 | 649 | 10/2/2025 |