csharp.md

August 3, 2026 ยท View on GitHub

Output Layout

C# output is one .cs file per schema, for example:

  • <csharp_out>/addressbook/Addressbook.cs

The C# model file name uses the normalized PascalCase source file stem. For example, service.fdl generates Service.cs, order-events.fdl generates OrderEvents.cs, and 123-schema.fdl generates Schema123Schema.cs.

Type Generation

Messages generate [ForyStruct] classes with C# properties and byte helpers:

[ForyStruct]
public sealed partial class Person
{
    public string Name { get; set; } = string.Empty;
    public int Id { get; set; }
    public List<Person.PhoneNumber> Phones { get; set; } = new();
    public Animal Pet { get; set; } = null!;

    public byte[] ToBytes() { ... }
    public static Person FromBytes(byte[] data) { ... }
}

Unions generate [ForyUnion] ADTs. Unknown(UnknownCase) is the Fory-provided forward-compatibility carrier marked with [ForyUnknownCase]. The marker only selects the carrier and does not add an entry to the schema case table. Schema-defined cases use non-negative [ForyCase] IDs. If a case needs non-default schema encoding, the generated [ForyCase] carries Type. Known case record names are PascalCase FDL case names; payload types are emitted as qualified references when needed to avoid name conflicts. A typed union must have at least one non-Unknown case.

[ForyUnion]
public abstract partial record Animal
{
    private Animal() {}

    [ForyUnknownCase]
    public sealed partial record Unknown(UnknownCase Value) : Animal;

    [ForyCase(0)]
    public sealed partial record Dog(global::addressbook.Dog Value) : Animal;

    [ForyCase(1)]
    public sealed partial record Cat(global::addressbook.Cat Value) : Animal;
}

Module Installation

Each schema generates a module class that installs imported modules first and then registers the local schema types:

public static class AddressbookForyModule
{
    public static void Install(Fory fory)
    {
        fory.Register<addressbook.Animal>((uint)106);
        fory.Register<addressbook.Person>((uint)100);
        // ...
    }
}

The C# model file basename and module class both use the normalized source file stem. They do not use csharp_namespace and they do not use gRPC service names. For example, service.fdl generates Service.cs and ServiceForyModule, while order-events.fdl generates OrderEvents.cs and OrderEventsForyModule. A gRPC service named Greeter generates the service companion GreeterGrpc.cs; it does not change the schema module name. To get GreeterForyModule, name the schema file greeter.fdl or Greeter.fdl.

This source-file rule lets several schemas target the same C# namespace without colliding. No namespace-derived or service-derived module alias is generated.

When explicit type IDs are not provided, generated installation uses computed numeric IDs (same behavior as other targets).

gRPC Service Companions

With --grpc, C# emits one <ServiceName>Grpc.cs per service. Its static service holder contains descriptors, <ServiceName>Base, <ServiceName>Client, and both BindService overloads. See C# gRPC for hosting, clients, dependencies, and streaming.