# 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.17.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()
    .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/)
