[英]How do i create a cpp function that can be called from c# with a function as an argument
Exactly as in the question. 与问题完全相同。
I have a pair of libraries, one in cpp, the other in c#. 我有一对库,一个在cpp中,另一个在c#中。 I already have several (cpp) functions that i can call from c#, but only with simple arguments (arrays and primitives).
我已经有几个(cpp)函数,可以从c#调用,但只能使用简单的参数(数组和基元)。
How do i pass a function? 如何传递功能?
I've read loads of answers on here, and none of them are helping me out - what am i missing? 我在这里读了很多答案,但是没有一个人在帮助我-我想念什么?
Here's what i have: 这是我所拥有的:
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;
}
And this all compiles, but i've not been able to test it yet, since i can't call it from the c#; 所有这些都可以编译,但是我还不能测试它,因为我不能从c#调用它。 this is what i've tried:
这是我尝试过的:
CostDelegate costDelegate = new CostDelegate(cost);
XXXCpp.Minimization.LevMar(costDelegate, x0, xhigh, xlow, 1000);
But it's telling me it cannot cast from 'CostDelegate' to 'ManagedFunction'. 但这告诉我它不能从“ CostDelegate”转换为“ ManagedFunction”。 Both are delegates, and both have the same signatures.
两者都是委托,并且都具有相同的签名。
How can i achieve what i wawnt here? 我如何才能在这里实现自我?
Is there a way to do it so that in the c#, when i call the function i can just pass it a function without having to create a delegate too (ie can i write the cpp such that the function takes a Func<double[], double>
instead of this 'ManagedFunction' object)? 有没有办法做到这一点,以便在c#中,当我调用该函数时,我可以仅将其传递给一个函数而不必创建委托(即,我可以编写cpp以便该函数使用
Func<double[], double>
而不是此“ ManagedFunction”对象)?
delegate double ManagedFunction(cli::array<System::Double>^ xIn);
You forgot to declare it public
. 您忘了宣布它为
public
。 Required, two delegate types are never compatible, not even when their signature is the same. 必需,两个委托类型永远不兼容,即使它们的签名相同也是如此。 Your C# code must create a ManagedFunction delegate, it can only do so when you make it public.
您的C#代码必须创建ManagedFunction委托,只有在将其公开后才能这样做。 Consider
Action<array<double>^>^
instead, but do read the next bullet. 考虑使用
Action<array<double>^>^
代替,但请阅读下一个项目符号。
Some other quirks that you need to pay attention to: 您需要注意的其他一些怪癖:
Beware of the calling convention that the native code assumes on the function pointer. 注意本机代码在函数指针上采取的调用约定。 The default is __cdecl, your delegate however is only compatible with __stdcall.
默认值为__cdecl,但是您的委托仅与__stdcall兼容。 If it is not __stdcall then you must apply the [UnmanagedFunctionPointer] attribute to declare the calling convention.
如果不是__stdcall,则必须应用[UnmanagedFunctionPointer]属性来声明调用约定。
A very tricky issue with the stubPointer variable is that it can become invalid before you make the native function call. stubPointer变量的一个非常棘手的问题是,在调用本机函数之前,它可能变得无效。 That will happen, very rarely, when other threads in your program run managed code and one of them triggers a garbage collection.
当程序中的其他线程运行托管代码并且其中一个触发垃圾回收时,这种情况很少发生。 You must write GC::KeepAlive(function);
您必须编写GC :: KeepAlive(function); after the function call to ensure this cannot go wrong, that extends the reported lifetime of the delegate object.
在确保确保不会出错的函数调用之后,这将延长报告的委托对象的生存期。
Copying the arrays is inefficient and not necessary. 复制数组效率低下,没有必要。 You can use
pin_ptr<double>
to avoid this. 您可以使用
pin_ptr<double>
避免这种情况。 That generates a pointer to the first element of the array and pins it for the lifetime of the function body. 这将生成一个指向数组第一个元素的指针,并将其固定在函数体的整个生命周期中。 The native code addresses the array elements directly from the GC heap.
本机代码直接从GC堆寻址数组元素。
您是否已阅读过如何:定义和使用委托(C ++ / CLI) ?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.