C# / .NET — in 5 Minuten zum ersten Sample
.NET 8. P/Invoke gegen die C-API in libzerodds. Idiomatic C# (records, async/await, IDisposable). IDL→C#-Codegen via zerodds-idlc generate --lang csharp; der erzeugte Code ruft den XCDR2-Codec in ZeroDds.Wire.
5-Minuten-Quickstart
libzerodds als Native-Dep, NuGet-Package, ~20 Zeilen C#.
1 · Native-Lib + C#-Binding installieren
Das Binding kommt von NuGet (ZeroDDS, mit ZeroDDS.Cdr und ZeroDds.Wire). Die native Bibliothek libzerodds ist nicht im Paket; sie kommt aus den Systempaketen oder aus dem Source.
Schritt 1a: libzerodds Runtime holen — pre-built oder Source:
# Ubuntu/Debian (amd64; arm64: _arm64.deb)
wget https://github.com/zero-objects/zero-dds/releases/download/v1.0.0-rc.7/zerodds-core_1.0.0-rc.7_amd64.deb
sudo dpkg -i zerodds-core_1.0.0-rc.7_amd64.deb
# Fedora/RHEL: die RPMs von rc.7 lassen sich nicht installieren (zerodds-core verlangt libzerodds.so()(64bit), das kein Paket bereitstellt); aus der Quelle bauen, siehe User Guide
# Arch: yay -S zerodds-bin
# macOS, Windows: libzerodds ist in keinem vorgebauten Paket (.pkg, MSI und Zip enthalten nur die Programme); aus dem Source bauen (unten)
# Aus Source (Entwicklung):
git clone https://github.com/zero-objects/zero-dds.git
cd zero-dds && cargo build --release -p zerodds-c-api
Schritt 1b: Projekt anlegen, C#-Binding von NuGet:
dotnet new console -o zerodds-hello
cd zerodds-hello
dotnet add package ZeroDDS --version 1.0.0-rc.7
2 · Pub/Sub-Roundtrip (Program.cs)
using ZeroDDS;
var factory = DomainParticipantFactory.Instance;
var participant = factory.CreateParticipant(0);
var topic = participant.CreateBytesTopic("Chatter");
var publisher = participant.CreatePublisher();
var subscriber = participant.CreateSubscriber();
using var writer = publisher.CreateBytesWriter(topic);
using var reader = subscriber.CreateBytesReader(topic);
writer.WaitForMatchedSubscription(1, TimeSpan.FromSeconds(5));
reader.WaitForMatchedPublication(1, TimeSpan.FromSeconds(5));
writer.Write("hello"u8.ToArray());
reader.WaitForData(TimeSpan.FromSeconds(3));
foreach (var payload in reader.Take())
{
Console.WriteLine($"got: {System.Text.Encoding.UTF8.GetString(payload)}");
}
▶ Runnable example: csharp-quickstart
3 · Laufen
dotnet run
# got: hello
Installation
Über NuGet
dotnet add package ZeroDDS --version 1.0.0-rc.7
# zieht ZeroDDS.Cdr (Vertrag der erzeugten TypeSupport-Klassen) und ZeroDds.Wire (XCDR2-Codec) mit
Über Source
git clone https://github.com/zero-objects/zero-dds.git
cd zero-dds/crates/cs/csharp
dotnet build ZeroDDS/ZeroDDS.csproj -c Release
# DLL unter ZeroDDS/bin/Release/net8.0/
# im eigenen Projekt: dotnet add reference path/to/zero-dds/crates/cs/csharp/ZeroDDS/ZeroDDS.csproj
Native-Lib finden
libzerodds.{so,dylib,dll} muss zur Laufzeit auffindbar sein. Drei Optionen:
- System-Install (
/usr/lib/libzerodds.sovia DEB/RPM) LD_LIBRARY_PATH=/path/to/lib dotnet run- Neben das Binary kopieren (
bin/Release/net8.0/libzerodds.so)
Typisierte Topics — zerodds-idlc generate --lang csharp
IDL (temperature.idl)
module sensor_msgs {
module msg {
struct Temperature {
long celsius;
string sensor_id;
};
};
};
Codegen + Use
zerodds-idlc generate --lang csharp --out Gen/ temperature.idl
# schreibt Gen/temperature.cs und Gen/temperature.TypeSupport.cs
// Nutzen
using sensor_msgs.msg;
var topic = participant.CreateTypedTopic<Temperature>("Temp");
var writer = publisher.CreateTypedWriter<Temperature>(topic);
writer.Write(new Temperature { Celsius = 23, Sensor_id = "A7" });
▶ Runnable example: csharp-typed
Neben dem Typ schreibt zerodds-idlc die Klasse TemperatureTypeSupport, eine IDdsTopicType<Temperature> aus ZeroDDS.Cdr; sie ruft den XCDR2-Codec in ZeroDds.Wire. Der IDL-Member sensor_id heißt dort Sensor_id. CreateTypedTopic<T>(name) findet die Klasse über ihren Namen <T>TypeSupport; CreateTypedTopic(name, TemperatureTypeSupport.Instance) übergibt sie direkt.
async/await
await writer.WriteAsync(payload, ct);
await reader.WaitForDataAsync(TimeSpan.FromSeconds(3), ct);
await foreach (var sample in reader.TakeAsync(ct))
{
Console.WriteLine(sample);
}
▶ Runnable example: csharp-async
Cancellation-Token wird durchgereicht; OperationCanceledException beim Cancel.
NativeAOT
Die P/Invoke-Schicht ist für NativeAOT geschrieben: Jeder DllImport nennt seinen EntryPoint, ohne Reflection (Native.cs), und die Listener-Callbacks sind [UnmanagedCallersOnly]-Methoden ohne Delegate-Marshalling (Listener.cs).
CreateTypedTopic<T>(name) sucht die TypeSupport-Klasse dagegen per Reflection. Wo Reflection nicht zur Verfügung steht, übergibt man sie direkt:
var topic = participant.CreateTypedTopic("Temp", TemperatureTypeSupport.Instance);
C# / .NET — first sample in 5 minutes
.NET 8. P/Invoke against the C API in libzerodds. Idiomatic C# (records, async/await, IDisposable). IDL→C# codegen via zerodds-idlc generate --lang csharp; the generated code calls the XCDR2 codec in ZeroDds.Wire.
5-minute quickstart
libzerodds as a native dep, the NuGet package, ~20 lines of C#.
1 · Install the native lib + C# binding
The binding comes from NuGet (ZeroDDS, with ZeroDDS.Cdr and ZeroDds.Wire). The native library libzerodds is not in the package; it comes from the system packages or from source.
Step 1a: get the libzerodds runtime — pre-built or source:
# Ubuntu/Debian (amd64; arm64: _arm64.deb)
wget https://github.com/zero-objects/zero-dds/releases/download/v1.0.0-rc.7/zerodds-core_1.0.0-rc.7_amd64.deb
sudo dpkg -i zerodds-core_1.0.0-rc.7_amd64.deb
# Fedora/RHEL: the rc.7 RPMs cannot be installed (zerodds-core requires libzerodds.so()(64bit), which no package provides); build from source, see the User Guide
# Arch: yay -S zerodds-bin
# macOS, Windows: libzerodds is in no pre-built package (.pkg, MSI and zip carry only the programs); build it from source (below)
# From source (development):
git clone https://github.com/zero-objects/zero-dds.git
cd zero-dds && cargo build --release -p zerodds-c-api
Step 1b: create the project, the C# binding from NuGet:
dotnet new console -o zerodds-hello
cd zerodds-hello
dotnet add package ZeroDDS --version 1.0.0-rc.7
2 · Pub/sub roundtrip (Program.cs)
using ZeroDDS;
var factory = DomainParticipantFactory.Instance;
var participant = factory.CreateParticipant(0);
var topic = participant.CreateBytesTopic("Chatter");
var publisher = participant.CreatePublisher();
var subscriber = participant.CreateSubscriber();
using var writer = publisher.CreateBytesWriter(topic);
using var reader = subscriber.CreateBytesReader(topic);
writer.WaitForMatchedSubscription(1, TimeSpan.FromSeconds(5));
reader.WaitForMatchedPublication(1, TimeSpan.FromSeconds(5));
writer.Write("hello"u8.ToArray());
reader.WaitForData(TimeSpan.FromSeconds(3));
foreach (var payload in reader.Take())
{
Console.WriteLine($"got: {System.Text.Encoding.UTF8.GetString(payload)}");
}
▶ Runnable example: csharp-quickstart
3 · Run
dotnet run
# got: hello
Installation
Via NuGet
dotnet add package ZeroDDS --version 1.0.0-rc.7
# pulls in ZeroDDS.Cdr (the contract of the generated TypeSupport classes) and ZeroDds.Wire (the XCDR2 codec)
Via source
git clone https://github.com/zero-objects/zero-dds.git
cd zero-dds/crates/cs/csharp
dotnet build ZeroDDS/ZeroDDS.csproj -c Release
# DLL under ZeroDDS/bin/Release/net8.0/
# in your own project: dotnet add reference path/to/zero-dds/crates/cs/csharp/ZeroDDS/ZeroDDS.csproj
Finding the native lib
libzerodds.{so,dylib,dll} must be discoverable at runtime. Three options:
- System install (
/usr/lib/libzerodds.sovia DEB/RPM) LD_LIBRARY_PATH=/path/to/lib dotnet run- copy it next to the binary (
bin/Release/net8.0/libzerodds.so)
Typed topics — zerodds-idlc generate --lang csharp
IDL (temperature.idl)
module sensor_msgs {
module msg {
struct Temperature {
long celsius;
string sensor_id;
};
};
};
Codegen + use
zerodds-idlc generate --lang csharp --out Gen/ temperature.idl
# writes Gen/temperature.cs and Gen/temperature.TypeSupport.cs
// use it
using sensor_msgs.msg;
var topic = participant.CreateTypedTopic<Temperature>("Temp");
var writer = publisher.CreateTypedWriter<Temperature>(topic);
writer.Write(new Temperature { Celsius = 23, Sensor_id = "A7" });
▶ Runnable example: csharp-typed
Beside the type, zerodds-idlc writes the class TemperatureTypeSupport, an IDdsTopicType<Temperature> from ZeroDDS.Cdr; it calls the XCDR2 codec in ZeroDds.Wire. The IDL member sensor_id is Sensor_id there. CreateTypedTopic<T>(name) finds the class by its name <T>TypeSupport; CreateTypedTopic(name, TemperatureTypeSupport.Instance) passes it directly.
async/await
await writer.WriteAsync(payload, ct);
await reader.WaitForDataAsync(TimeSpan.FromSeconds(3), ct);
await foreach (var sample in reader.TakeAsync(ct))
{
Console.WriteLine(sample);
}
▶ Runnable example: csharp-async
The cancellation token is threaded through; OperationCanceledException on cancel.
NativeAOT
The P/Invoke layer is written for NativeAOT: every DllImport names its EntryPoint, with no reflection (Native.cs), and the listener callbacks are [UnmanagedCallersOnly] methods with no delegate marshalling (Listener.cs).
CreateTypedTopic<T>(name), by contrast, looks the TypeSupport class up by reflection. Where reflection is not available, pass it directly:
var topic = participant.CreateTypedTopic("Temp", TemperatureTypeSupport.Instance);