Skip to content

C# Bindings

C# bindings let your Rust library be used from .NET applications.

The template uses csbindgen to automatically generate .NET wrapper classes, handling cross-platform library loading and calling conventions so you can focus on writing Rust code.

The bindings are generated from the C Exports; with precompiled binaries for all supported CoreCLR platforms, including Windows, Linux and macOS.

Example Bindings

Generated C# Bindings (NativeMethods.g.cs)
// <auto-generated>
// This code is generated by csbindgen.
// DON'T CHANGE THIS DIRECTLY.
// </auto-generated>
#pragma warning disable CS8500
#pragma warning disable CS8981
using System;
using System.Runtime.InteropServices;

namespace prs_rs.Net.Sys;

public static unsafe partial class NativeMethods
{
    const string __DllName = "prs_rs";

    /// <summary>
    ///  Compresses the given data in `source`, placing it in `destimation`.
    ///
    ///  Parameters
    ///
    ///  - `src`: A pointer to the compressed data.
    ///  - `src_len`: Length of the compressed data.
    ///  - `destination`: A pointer to the decompressed data to be written.
    ///
    ///  # Returns
    ///
    ///  Number of bytes written to `destination`.
    ///
    ///  # Safety
    ///
    ///  It's safe as long as `dest` has sufficient length (max length: [`prs_calculate_max_compressed_size`])
    ///  and the remaining parameters are valid.
    /// </summary>
    [DllImport(__DllName, EntryPoint = "prs_compress", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
    public static extern nuint prs_compress(byte* src, byte* dest, nuint src_len);

    /// <summary>
    ///  Decompresses PRS compressed data, in an unsafe manner, without any error handling.
    ///
    ///  # Parameters
    ///
    ///  - `source`: A pointer to the compressed data.
    ///  - `destination`: A pointer to the decompressed data.
    ///
    ///  # Returns
    ///
    ///  - The length of the decompressed data.
    ///
    ///  # Safety
    ///
    ///  Function is safe as long as the source points to valid PRS compressed data with
    ///  a terminator byte. The destination should be large enough to store the decompressed data.
    /// </summary>
    [DllImport(__DllName, EntryPoint = "prs_decompress", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
    public static extern nuint prs_decompress(byte* src, byte* dest);
}

The generated bindings include proper P/Invoke declarations with cross-platform calling conventions.

How to Export Functions

C# bindings are generated from C bindings, so the same export rules apply.

See C/C++ Bindings - How to Export Functions for detailed examples and best practices.

Automatic Binding Generation

Info

Your C# bindings are automatically generated and packaged when you build your project.

Generate bindings locally:

cd src
cargo build --features c-exports  # Generate C# bindings and NuGet package

Bindings are placed in bindings/csharp/NativeMethods.g.cs.

When you build your project, bindings are generated with csbindgen and a NuGet package is created with precompiled binaries for all supported platforms. The package includes the generated P/Invoke declarations and native libraries for Windows, Linux, and macOS.

The NuGet package is automatically published to nuget.org when you create a release tag.

Version Management

Warning

C# NuGet package versions must be manually synchronized with Rust crate versions.

The C# NuGet package version in bindings/csharp/csharp.csproj is not automatically synchronized with your Rust crate version. When you release a new version:

  1. Update Rust Version: Bump the version in Cargo.toml
  2. Update C# Version: Manually update the <Version> in bindings/csharp/csharp.csproj to match
  3. Create Release Tag: Push a tag with the new version number

This is because there may be multiple projects in a single repo- with their own versions.

Integration with Existing Projects

Info

Add C# bindings to existing projects by copying configuration files from the template.

1. Generate Template Files

First, generate a fresh template to get the latest configuration files:

cargo generate --git https://github.com/Reloaded-Project/reloaded-templates-rust.git

2. Copy Configuration Files

Copy these key files from the generated template to your existing project:

  • bindings/csharp/NativeMethods.cs - DllImportResolver implementation
  • bindings/csharp/Init.cs - Module initializer
  • bindings/csharp/csharp.csproj - C# project configuration
  • bindings/csharp/.gitignore - Version control rules
  • Relevant sections from Cargo.toml and build.rs for csbindgen integration

3. Update Project Configuration

Add csbindgen to your build dependencies in Cargo.toml:

[build-dependencies]
csbindgen = "1.9.0"

Modify your build.rs to generate C# bindings:

fn main() {
    csbindgen::Builder::default()
        .input_extern_file("src/exports.rs")
        .csharp_dll_name("your_library_name")
        .csharp_class_accessibility("public")
        .csharp_namespace("YourLibrary.Net.Sys")
        .generate_csharp_file("../bindings/csharp/NativeMethods.g.cs")
        .unwrap();
}

See the main documentation for more details on getting started with cargo-generate.