如何使用SWIG将C#中可传递IEnumerable参数的委托转换为C++中可接受的委托?

17

我有以下C++代码:

#ifdef WIN32
#  undef CALLBACK
#  define CALLBACK __stdcall
#else
#  define CALLBACK
#endif


#include <iostream>
#include <vector>

namespace OdeProxy {

    typedef std::vector< double > state_type;
    typedef void (CALLBACK *System)( const state_type &, state_type &, const double);
    typedef void (CALLBACK *Observer)( const state_type &, double);

    class Ode {
    public:
        state_type initialConditions;
        System system;
        Observer observer;
        double from;
        double to;
        double step;
    };
}

关于 .i 文件:

/* File : MyProject.i */
%module MyProject

%{
#include "C++/OdeProxy.h"
%}

%include "std_vector.i"
%include "C++/OdeProxy.h"

%template(state_type) std::vector<double>;


//// Delegate realated stuff ////
%typemap(cstype) void (*)( const state_type &, state_type &, const double) "SystemDelegate";
%typemap(imtype) void (*)( const state_type &, state_type &, const double) "SystemDelegate";

%typemap(cstype) void (*)( const state_type &, double) "ObserverDelegate";
%typemap(imtype) void (*)( const state_type &, double) "ObserverDelegate";

我受到这个帖子的启发而创建了代码生成器。

然而我不知道如何生成像这样的代码:

using OdeLibrary;

namespace OdeTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //var lam = new OdeLibrary.SWIGTYPE_p_f_r_q_const__std__vector__double___double__void()
            var ode = new Ode{
                from = 0,
                to = 10,
                initialConditions = new state_type(new[]{1,2,3}),
                step = 0.01,
                observer = (x, dxdt, t) => { return; }
           };
        }
    }
}

编译错误:

Error   Cannot convert lambda expression to type 'OdeLibrary.SWIGTYPE_p_f_r_q_const__std__vector__double___double__void' because it is not a delegate type

其中SWIGTYPE_p_f_r_q_const__std__vector__double___double__void看起来像这样:

/* ----------------------------------------------------------------------------
 * This file was automatically generated by SWIG (http://www.swig.org).
 * Version 2.0.9
 *
 * Do not make changes to this file unless you know what you are doing--modify
 * the SWIG interface file instead.
 * ----------------------------------------------------------------------------- */

namespace OdeLibrary {

using System;
using System.Runtime.InteropServices;

public class SWIGTYPE_p_f_r_q_const__std__vector__double___double__void {
  private HandleRef swigCPtr;

  internal SWIGTYPE_p_f_r_q_const__std__vector__double___double__void(IntPtr cPtr, bool futureUse) {
    swigCPtr = new HandleRef(this, cPtr);
  }

  protected SWIGTYPE_p_f_r_q_const__std__vector__double___double__void() {
    swigCPtr = new HandleRef(null, IntPtr.Zero);
  }

  internal static HandleRef getCPtr(SWIGTYPE_p_f_r_q_const__std__vector__double___double__void obj) {
    return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr;
  }
}

}

我想知道在.i文件中需要做出哪些更改,或者在C#生成的包装程序中需要添加什么,才能将我的C# lambda表达式作为委托传递给C++类?


你尝试过使用new Func<>而不是lambda表达式吗? - Dustin Kingen
1
如何创建可继承的 Ode,其中包含 protectedvirtual 成员 systemobserver,在 C# 实现中对其进行重载,并为 publicSystem/Observer Actions<IEnumerable...> 提供 get/set - DuckQueen
1个回答

5

我已将此功能应用于以下配置:

public class StateTypeCustomMarshaller : ICustomMarshaler
{
    public static ICustomMarshaler GetInstance(string s)
    {
        return new StateTypeCustomMarshaller();
    }

    public object MarshalNativeToManaged(IntPtr pNativeData)
    {
        return new state_type(pNativeData, false);
    }

    public IntPtr MarshalManagedToNative(object ManagedObj)
    {
        throw new NotImplementedException();
    }

    public void CleanUpNativeData(IntPtr pNativeData)
    {
        throw new NotImplementedException();
    }

    public void CleanUpManagedData(object ManagedObj)
    {
    }

    public int GetNativeDataSize()
    {
        throw new NotImplementedException();
    }
}

public delegate void ObserverDelegate(
        [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StateTypeCustomMarshaller))]state_type state,
        double d);

相应的.i文件是:

/* File : MyProject.i */
%module MyProject

%include "std_vector.i"
%template(state_type) std::vector<double>;

//// Delegate realated stuff ////
%typemap(csin) void (*)(OdeProxy::state_type&, double) "$csinput";
%typemap(cstype) void (*)(OdeProxy::state_type&,double) "ConsoleApplication2.Helpers.ObserverDelegate";
%typemap(imtype) void (*)(OdeProxy::state_type&, double) "ConsoleApplication2.Helpers.ObserverDelegate";
%typemap(csvarout) void (*)(OdeProxy::state_type&, double) %{
get {
  return $imcall;
} %}

%{
    #include "OdeProxy.h"
%}

%include "OdeProxy.h"

注意:我已经尝试使用非常量引用来引用状态类型,但是使用常量引用也可以工作。


1
我实际上采用了继承方案(类似于DuckQueen所描述的)。最终创建了这个开源库 - myWallJSON
@myWallJSON 謝謝您告訴我們有關這個庫和您的解決方案。很高興知道這些。 - FrostyFire

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接