You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#程序中调用依赖多文件的Rust库函数?

在C#中调用Rust库的create函数步骤

要在C#里调用这个Rust函数,核心是把Rust库导出为C兼容的接口,再通过C#的P/Invoke机制调用,具体操作如下:

1. 改造Rust代码,导出C兼容接口

原函数依赖Rust专属的Config、Path等类型,无法直接被C#调用,需要封装一层C兼容的接口:

1.1 定义C兼容的数据结构

在Rust库中添加C兼容的结构体和枚举,替代原有的Rust类型:

use std::os::raw::{c_int, c_char};
use std::ffi::{CStr, CString};
use std::path::Path;

// 对应原Config的C兼容结构体
#[repr(C)]
pub struct CConfig {
    verbose: c_int, // 用int代替bool,C中bool通常以int表示
    game_id: c_int, // 用枚举值标识游戏类型,比如0=GameA,1=GameB等
}

// 定义游戏类型枚举,和C#端保持一致
#[repr(C)]
pub enum CGameType {
    GameA,
    GameB,
}

1.2 封装导出函数

添加#[no_mangle]标记的函数,负责把C类型转换为Rust内部类型,调用原create函数,并返回错误码(0=成功,非0=失败):

#[no_mangle]
pub extern "C" fn create_mod_pack(c_config: CConfig, c_path: *const c_char) -> c_int {
    // 转换C字符串为Rust Path
    let path = unsafe {
        if c_path.is_null() {
            return 1; // 路径为空返回错误
        }
        CStr::from_ptr(c_path).to_str().map_err(|_| 2)?
    };
    let path = Path::new(path);

    // 转换CConfig为原Config类型
    let config = Config {
        verbose: c_config.verbose != 0,
        game: Some(match c_config.game_id {
            x if x == CGameType::GameA as c_int => Game::GameA,
            x if x == CGameType::GameB as c_int => Game::GameB,
            _ => return 3, // 无效游戏类型返回错误
        }),
    };

    // 调用原create函数,处理结果
    match create(&config, path) {
        Ok(_) => 0,
        Err(e) => {
            eprintln!("Error creating mod pack: {}", e);
            4 // 通用错误码
        }
    }
}

1.3 配置Cargo.toml

确保Rust库编译为动态链接库,在Cargo.toml中添加:

[lib]
crate-type = ["cdylib"] # 编译为C兼容的动态链接库

2. 编译Rust库

执行编译命令生成对应平台的动态链接库:

cargo build --release

编译完成后,在target/release目录下会得到对应的文件(Windows为.dll,Linux为.so,macOS为.dylib)。

3. 在C#中调用该动态链接库

3.1 定义对应的数据结构和枚举

在C#中定义和Rust端内存布局一致的结构体和枚举:

using System;
using System.Runtime.InteropServices;

// 对应Rust的CGameType枚举
public enum CGameType
{
    GameA,
    GameB
}

// 对应Rust的CConfig结构体
[StructLayout(LayoutKind.Sequential)]
public struct CConfig
{
    public int verbose;
    public int game_id;
}

3.2 导入Rust导出的函数

用DllImport导入动态链接库中的函数:

public class RustModPackApi
{
    // 替换为你的Rust库文件名
    [DllImport("your_lib_name.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int create_mod_pack(CConfig config, string path);
}

3.3 调用函数

在C#代码中构造参数并调用:

var config = new CConfig
{
    verbose = 1, // 1表示开启verbose,0关闭
    game_id = (int)CGameType.GameA
};

string modPackPath = @"C:\path\to\mod.pack";
int result = RustModPackApi.create_mod_pack(config, modPackPath);

if (result == 0)
{
    Console.WriteLine("Mod pack created successfully");
}
else
{
    Console.WriteLine($"Failed to create mod pack, error code: {result}");
}

注意事项

  • 内存管理:如果Rust函数需要返回字符串给C#,需额外提供内存释放函数;本场景无需返回数据,只需关注输入参数转换。
  • 编码一致性:确保Rust和C#使用相同的字符串编码,若需UTF-8,可在C#的DllImport中添加CharSet = CharSet.Unicode并调整Rust端字符串处理逻辑。
  • 平台适配:不同操作系统对应不同的库文件格式,C#代码需根据运行平台加载对应库文件。

内容的提问来源于stack exchange,提问作者romanCastro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 01:05:46