SkillAgentSearch skills...

FastCloner

The fastest deep cloning library for .NET – zero-config, works out of the box.

Install / Use

/learn @lofcz/FastCloner

README

<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 FastCloner License:MIT

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.Json and 160x vs System.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, or Ignore, 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)

  1. Runtime SetTypeBehavior<T>()
  2. Member-level attribute
  3. Type-level attribute on member's type
  4. 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 referen

Related Skills

View on GitHub
GitHub Stars342
CategoryDevelopment
Updated5d ago
Forks11

Languages

C#

Security Score

100/100

Audited on Mar 28, 2026

No findings