blob: 431c8b08ce354561679a78f3482376aec9ccfef7 [file] [view]
---
title: C#
sidebar_position: 7
id: csharp
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---
## 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:
```csharp
[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.
```csharp
[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:
```csharp
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](../../grpc/csharp.md) for hosting, clients, dependencies, and streaming.