2016-01-25 44 views
0

与问题完全相同。如何创建一个可以从c#调用的cpp函数作为参数

我有一对库,一个在cpp中,另一个在c#中。我已经有几个(cpp)函数可以从c#调用,但只有简单的参数(数组和基元)。

如何传递函数?

我已经阅读了大量的答案在这里,他们都没有帮助我 - 我失踪了什么?

下面是我有:

delegate double ManagedFunction(cli::array<System::Double>^ xIn); 
    ... 

    ... 
    static int LevMar(
     ManagedFunction^ function, 
     cli::array<System::Double, 1>^ x0, 
     cli::array<System::Double, 1>^ xHigh, 
     cli::array<System::Double, 1>^ xLow, 
     int maxIters//, 
     //double tolerance 
     ) { 

     IntPtr stubPointer = Marshal::GetFunctionPointerForDelegate(function); 
     Unmanaged::WrapperClass::functionToMinimize = static_cast<Unmanaged::UnmanagedFunction>(stubPointer.ToPointer()); 

     int m = x0->Length; //nDim 
     int N = 1; //observables dimension 

     double* fx = new double[m]; 

     double* x0Arr = Utility::CreateDoubleArrayFromManaged(x0); 
     double* xLowArr = Utility::CreateDoubleArrayFromManaged(xLow); 
     double* xHighArr = Utility::CreateDoubleArrayFromManaged(xHigh); 

     double info[LM_INFO_SZ]; 


     double tolerance[5]; 
     tolerance[0] = 0.01; //scale factor for initial \mu/ 
     tolerance[1] = tolerance[2] = tolerance[3] = tolerance[4] = 1.0e-5; 

     dlevmar_bc_dif(Unmanaged::WrapperClass::functionToPassToLevMar, x0Arr, fx, m, N, xLowArr, xHighArr, NULL, maxIters, tolerance, info, NULL, NULL, NULL); 
     int nElements = sizeof x0Arr/sizeof x0Arr[0]; 
     for (int i = 0; i < nElements; i++) x0[i] = x0Arr[0]; 
     return 0; 
    } 

而这一切编译,但我没能还没有测试它,因为我不能从C#调用它;这是我试过的:

CostDelegate costDelegate = new CostDelegate(cost); 
XXXCpp.Minimization.LevMar(costDelegate, x0, xhigh, xlow, 1000); 

但它告诉我它不能从'CostDelegate'投射到'ManagedFunction'。两者都是代表,并且都具有相同的签名。

我怎样才能实现我在这里的东西?

有没有办法做到这一点,以便在C#中,当我调用函数,我可以只是传递一个函数,而不必创建一个委托(即我可以写的CPP,使功能需要Func<double[], double>而不是这个'ManagedFunction'对象)?

+0

从你的代码不是很清楚你想要做什么。例如。它们是什么类型的Unmanaged :: WrapperClass :: functionToPassToLevMar以及它分配的位置。你能否提供一个简单的例子,而不依赖于其他类? – opetroch

回答

1
delegate double ManagedFunction(cli::array<System::Double>^ xIn); 

您忘了声明public。如果需要,两种委托类型永远不会兼容,即使它们的签名是相同的。您的C#代码必须创建一个ManagedFunction委托,它只能在公开时这样做。改为Action<array<double>^>^,但请阅读下一个项目符号。

,你需要注意一些其他怪癖:

  • 谨防调用约定,本机代码假定函数指针的。默认是__cdecl,但是你的委托只与__stdcall兼容。如果它不是__stdcall,那么你必须应用[UnmanagedFunctionPointer]属性来声明调用约定。

  • stubPointer变量的一个非常棘手的问题是,在进行本机函数调用之前,它可能变得无效。当程序中的其他线程运行托管代码并且其中一个触发垃圾收集时,这种情况很少会发生。您必须编写GC :: KeepAlive(函数);在函数调用之后确保这不会出错,这扩展了委托对象的报告生命周期。

  • 复制数组效率低下且不必要。您可以使用pin_ptr<double>来避免这种情况。这会生成一个指向数组的第一个元素的指针,并将其固定在函数体的生命周期中。本地代码直接从GC堆寻址数组元素。

+0

好吧,所以我需要在c#中创建一个'ManagedFunction'并传递它。精细。我如何从'Func '我创建它? – will

+0

你是在谜语中发言,我只看到一个“CostDelegate”。如果你必须适应一个委托类型到另一个,那么使用lambda表达式。 –

+0

我的意思是我需要创建一个在cpp文件中定义的委托实例。它看起来像是我需要做的,我认为 – will

相关问题