blob: 456aeb86ed0ea8b10b515870c9561e0e77fd6ca9 [file] [log] [blame] [view]
# Apache Fory™ C\#
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/apache/fory/blob/main/LICENSE)
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.
## Why Apache Fory™ C\#?
- High-performance binary serialization for .NET 8+
- Cross-language compatibility with Java, Python, C++, Go, Rust, and JavaScript
- Source-generator-based serializers for `[ForyObject]` types
- Optional shared/circular reference tracking (`TrackRef(true)`)
- Compatible mode for schema evolution
- Thread-safe runtime wrapper (`ThreadSafeFory`) for concurrent workloads
- Dynamic object serialization APIs for heterogeneous payloads
## Quick Start
### Requirements
- .NET SDK 8.0+
- C# 12+
### Add Apache Fory™ C\#
From NuGet, reference the single `Apache.Fory` package. It includes the runtime plus the source generator for `[ForyObject]` types.
```xml
<ItemGroup>
<PackageReference Include="Apache.Fory" Version="0.16.0" />
</ItemGroup>
```
For local development against this repository, reference the runtime project and generator project directly:
```xml
<ItemGroup>
<ProjectReference Include="../fory/csharp/src/Fory/Fory.csproj" />
<ProjectReference
Include="../fory/csharp/src/Fory.Generator/Fory.Generator.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
```
### Basic Example
```csharp
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);
```
## Core Features
### 1. Object Graph Serialization
`[ForyObject]` types are serialized with generated serializers.
```csharp
[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);
```
### 2. Shared and Circular References
Enable reference tracking to preserve object identity.
```csharp
[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));
```
### 3. Schema Evolution
Compatible mode allows schema changes between writer and reader.
```csharp
[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" }));
```
### 4. Dynamic Object Serialization
Use dynamic APIs for unknown/heterogeneous payloads.
```csharp
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);
```
### 5. Thread-Safe Runtime
`Fory` is single-thread optimized. Use `ThreadSafeFory` for concurrent access.
```csharp
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);
});
```
### 6. Custom Serializers
Provide custom encoding logic with `Serializer<T>`.
```csharp
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);
```
## Cross-Language Serialization
Use consistent registration mappings across languages.
```csharp
Fory fory = Fory.Builder()
.Xlang(true)
.Compatible(true)
.Build();
fory.Register<Person>(100); // same ID on other language peers
```
See [xlang guide](https://fory.apache.org/docs/guide/xlang/) for mapping details.
## Documentation
- [C# guide index](https://fory.apache.org/docs/guide/csharp/)
- [Cross-language serialization spec](https://fory.apache.org/docs/specification/xlang_serialization_spec/)
- [Cross-language type mapping](https://fory.apache.org/docs/specification/xlang_type_mapping/)