2013-05-20 11 views
17

Così ho codice successivo C++:Come creare passabile da C# in delegato C++ che accetta un oggetto IEnumerable come argomento con SWIG?

#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; 
    }; 
} 

e il file .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"; 

ho creato di essere ispirato da questo thread. Il codice viene generato.

Eppure non riesco a capire come ottenere il codice come

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; } 
      }; 
     } 
    } 
} 

compilazione. Errore:

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 

Dove SWIGTYPE_p_f_r_q_const__std__vector__double___double__void assomiglia a questo:

/* ---------------------------------------------------------------------------- 
* 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; 
    } 
} 

} 

Allora mi chiedo che cosa è cambiato nel .i file o aggiunto al C# generato involucro per ottenere la possibilità di passare il mio C# lambda per classe C++ come delegato?

+0

Hai provato solo "nuova Funczza <>" invece di una lambda? – Romoku

+1

Che creazione di "Ode" ereditabile con 'protected'' virtual'members 'system' e' observer', overload tham in C# e implementazione 'get' /' set' per 'public'' System'/'Observer' 'azioni '? – DuckQueen

risposta

3

ottenuto questo lavorando per seguente configurazione:

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); 

corrispondente file .i per questo è:

/* 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" 

NOTA: ho provato con i non-costante riferimento a state-tipo, ma con riferimento costante funzionerà anche.

+1

In realtà sono andato con lo schema di ereditarietà (allo stesso modo descritto da DuckQueen). Si è conclusa la creazione di [questa libreria opensource] (https://github.com/OlegJakushkin/CSharpOdeLibrary) – myWallJSON

+0

@myWallJSON Grazie per aver detto di utilizzare la libreria e la soluzione. Buono a sapersi. – FrostyFire

Problemi correlati