Apache Fory™ is a blazing fast multi-language serialization framework powered by JIT compilation and zero-copy techniques.
The C# implementation provides high-performance object graph serialization for .NET with source-generated serializers, optional reference tracking, schema evolution support, and cross-language compatibility.
[ForyObject] typesTrackRef(true))ThreadSafeFory) for concurrent workloadsFrom NuGet, reference the single Apache.Fory package. It includes the runtime plus the source generator for [ForyObject] types.
<ItemGroup> <PackageReference Include="Apache.Fory" Version="0.16.0" /> </ItemGroup>
For local development against this repository, reference the runtime project and generator project directly:
<ItemGroup> <ProjectReference Include="../fory/csharp/src/Fory/Fory.csproj" /> <ProjectReference Include="../fory/csharp/src/Fory.Generator/Fory.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> </ItemGroup>
using Apache.Fory; [ForyObject] public sealed class User { public long Id { get; set; } public string Name { get; set; } = string.Empty; public string? Email { get; set; } } Fory fory = Fory.Builder().Build(); fory.Register<User>(1); User user = new() { Id = 1, Name = "Alice", Email = "alice@example.com", }; byte[] payload = fory.Serialize(user); User decoded = fory.Deserialize<User>(payload);
[ForyObject] types are serialized with generated serializers.
[ForyObject] public sealed class Address { public string Street { get; set; } = string.Empty; public int Zip { get; set; } } [ForyObject] public sealed class Person { public long Id { get; set; } public string Name { get; set; } = string.Empty; public List<Address> Addresses { get; set; } = []; } Fory fory = Fory.Builder().Build(); fory.Register<Address>(100); fory.Register<Person>(101);
Enable reference tracking to preserve object identity.
[ForyObject] public sealed class Node { public int Value { get; set; } public Node? Next { get; set; } } Fory fory = Fory.Builder().TrackRef(true).Build(); fory.Register<Node>(200); Node node = new() { Value = 7 }; node.Next = node; Node decoded = fory.Deserialize<Node>(fory.Serialize(node)); System.Diagnostics.Debug.Assert(object.ReferenceEquals(decoded, decoded.Next));
Compatible mode allows schema changes between writer and reader.
[ForyObject] public sealed class OneField { public string? F1 { get; set; } } [ForyObject] public sealed class TwoFields { public string F1 { get; set; } = string.Empty; public string F2 { get; set; } = string.Empty; } Fory fory1 = Fory.Builder().Compatible(true).Build(); fory1.Register<OneField>(300); Fory fory2 = Fory.Builder().Compatible(true).Build(); fory2.Register<TwoFields>(300); TwoFields decoded = fory2.Deserialize<TwoFields>(fory1.Serialize(new OneField { F1 = "hello" }));
Use dynamic APIs for unknown/heterogeneous payloads.
Fory fory = Fory.Builder().Build(); Dictionary<object, object?> map = new() { ["k1"] = 7, [2] = "v2", [true] = null, }; byte[] payload = fory.Serialize<object?>(map); object? decoded = fory.Deserialize<object?>(payload);
Fory is single-thread optimized. Use ThreadSafeFory for concurrent access.
using ThreadSafeFory fory = Fory.Builder().BuildThreadSafe(); fory.Register<User>(1); Parallel.For(0, 128, i => { byte[] payload = fory.Serialize(i); int decoded = fory.Deserialize<int>(payload); });
Provide custom encoding logic with Serializer<T>.
public sealed class PointSerializer : Serializer<Point> { public override Point DefaultValue => new(); public override void WriteData(WriteContext context, in Point value, bool hasGenerics) { context.Writer.WriteVarInt32(value.X); context.Writer.WriteVarInt32(value.Y); } public override Point ReadData(ReadContext context) { return new Point { X = context.Reader.ReadVarInt32(), Y = context.Reader.ReadVarInt32(), }; } } Fory fory = Fory.Builder().Build(); fory.Register<Point, PointSerializer>(400);
Use consistent registration mappings across languages.
Fory fory = Fory.Builder() .Xlang(true) .Compatible(true) .Build(); fory.Register<Person>(100); // same ID on other language peers
See xlang guide for mapping details.