如何在C#中调用参数包含函数类型的Rust导出函数
解决方案
问题原因
- Rust的
&dyn Fn是Rust特有动态分发trait对象,不兼容C ABI,无法和C#传递的非托管委托直接匹配 - 原有尝试实现返回了栈上临时变量的可变指针,属于未定义行为,且返回值类型和C#声明的int类型不匹配
正确的Rust实现
第一步 调整Cargo.toml配置
首先修改配置确保编译出C兼容的动态库:
[package] name = "rust_csharp_demo" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"]
第二步 编写导出函数
使用C ABI兼容的函数指针类型替代&dyn Fn即可:
fn operation(number: i32, f: impl Fn(i32) -> i32) -> i32 { f(number) } #[no_mangle] pub extern "C" fn c_operation(number: i32, f: extern "C" fn(i32) -> i32) -> i32 { // 外部传入的C兼容函数指针可直接作为Fn实现传入原有逻辑 operation(number, f) }
C#端适配(可选但推荐)
显式指定调用约定,避免不同平台默认规则不一致导致的栈异常:
const string RSTLIB = "../../PathOfDLL"; // 显式指定调用约定和Rust的extern "C"匹配 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int Fn(int number); [DllImport(RSTLIB, CallingConvention = CallingConvention.Cdecl)] static extern int c_operation(int x, Fn fn); int Square(int number) => number * number; int Cube(int number) => number * number * number; void Test() { Console.WriteLine("{0}", c_operation(5, Square)); // 输出25 Console.WriteLine("{0}", c_operation(7, Square)); // 输出49 Console.WriteLine("{0}", c_operation(3, Cube)); // 输出27 }
注意事项
- 编译Rust库时注意和C#运行的平台保持一致,C#跑x86就编译Rust x86版本,跑x64就对应x64版本,否则会出现DLL加载失败问题
- Linux/macOS平台需要把DLL路径替换为对应
.so/.dylib文件的路径
内容的提问来源于stack exchange,提问作者Alexandra Danith Ansley
相关产品推荐
相关产品推荐

