将C#实例方法作为回调传递给Rust?

将C#实例方法作为回调传递给Rust?,c#,rust,C#,Rust,我正试图将一个C#方法传递给Rust以用作回调。 我已经成功地传递了一个静态函数,它工作得很好(见下文) 现在我想调用一个实例方法,这意味着下面的trigger函数也应该接收一个不透明(libc::c_void)指针。 如何获取IntPtr哪个Rust应该作为回调函数的实例指针传递 C# 锈蚀: 使用std::boxed::Box; pub结构回调{ 回调:外部“stdcall”fn(i32), } impl-rust回调{ fn new(回调:extern“stdcall”fn(i32))->

我正试图将一个C#方法传递给Rust以用作回调。 我已经成功地传递了一个静态函数,它工作得很好(见下文)

现在我想调用一个实例方法,这意味着下面的
trigger
函数也应该接收一个不透明(
libc::c_void
)指针。 如何获取
IntPtr
哪个Rust应该作为回调函数的实例指针传递

C#

锈蚀:

使用std::boxed::Box;
pub结构回调{
回调:外部“stdcall”fn(i32),
}
impl-rust回调{
fn new(回调:extern“stdcall”fn(i32))->RustCallback{
锈迹斑斑{
回调:读取,
}
}
}
发布fn设置输出参数(输出:*mut T,值:T){
不安全{*out.as_mut().unwrap()=value};
}
#[没有损坏]
pub extern“C”fn create(回调:extern“stdcall”fn(i32),sc:*mut*mut RustCallback)->u32{
将输出参数(sc,Box::设置为原始值(Box::new(RustCallback::new(callback)));
0
}
#[没有损坏]
pub extern“C”fn触发器(sc:*mut RustCallback,x:i32)->u32{
设sc=unsafe{sc.as_mut().unwrap()};
设f=sc.read\u fn;
f(x);
0
}

如果我理解正确,您不需要这样做。只需将指针传递到实例方法,与对静态方法的传递方式完全相同-.net将为您处理它。@Evk它可以工作!谢谢,我甚至不想在没有实例指针的情况下尝试。你知道魔法是怎么起作用的吗?传递给Rust的指针是否指向CLR创建的包装器函数,CLR会记住该指针并在调用实例方法之前将其推送到堆栈中?基本上是的。net委托具有Target属性,因此它不是纯粹的函数指针。GetFunctionPointerForDelegate保留此语义。您可以在这里阅读更多内容:还要注意保持委托活动,否则垃圾收集器可能会在rust执行它之前(或期间)收集它,这将导致令人惊讶的结果。NET无法知道委托被非托管代码使用,所以您应该自己处理。尽管只有在回调可以在您传递回调之后执行时,保持活动状态才重要。如果rust只在传入回调的同一个函数中执行回调(不存储它以供以后使用)-.net应该让它自己保持活动状态。
    class Program
    {
        delegate void PrintFn(int x);

        public static void Main(string[] args)
        {
            PrintFn fn = Print;
            var ptr = Marshal.GetFunctionPointerForDelegate(fn);
            IntPtr handle = IntPtr.Zero;
            create(ptr, out handle);
            trigger(handle, 3);
        }

        public static void Print(int x)
        {
            Console.WriteLine($"C#: {x}");
        }

        [DllImport(@"/path/to/rust/dll")]
        public static extern int create(IntPtr readFn, out IntPtr callback);

        [DllImport(@"/path/to/rust/dll")]
        public static extern int trigger(IntPtr handle, int x);
    }
use std::boxed::Box;

pub struct RustCallback {
    callback: extern "stdcall" fn(i32),
}

impl RustCallback {
    fn new(callback: extern "stdcall" fn(i32)) -> RustCallback {
        RustCallback {
            callback: read_fn,
        }
    }
}

pub fn set_output_arg<T>(out: *mut T, value: T) {
    unsafe { *out.as_mut().unwrap() = value };
}

#[no_mangle]
pub extern "C" fn create(callback: extern "stdcall" fn(i32), sc: *mut *mut RustCallback)  -> u32 {
    set_output_arg(sc, Box::into_raw(Box::new(RustCallback::new(callback))));
    0
}

#[no_mangle]
pub extern "C" fn trigger(sc: *mut RustCallback, x: i32)  ->  u32 {
    let sc = unsafe { sc.as_mut().unwrap() };
    let f = sc.read_fn;
    f(x);
    0
}