繁体   English   中英

我如何创建可以从c#中调用的cpp函数,并将函数作为参数

[英]How do i create a cpp function that can be called from c# with a function as an argument

与问题完全相同。

我有一对库,一个在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”对象)?

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

您忘了宣布它为public 必需,两个委托类型永远不兼容,即使它们的签名相同也是如此。 您的C#代码必须创建ManagedFunction委托,只有在将其公开后才能这样做。 考虑使用Action<array<double>^>^代替,但请阅读下一个项目符号。

您需要注意的其他一些怪癖:

  • 注意本机代码在函数指针上采取的调用约定。 默认值为__cdecl,但是您的委托仅与__stdcall兼容。 如果不是__stdcall,则必须应用[UnmanagedFunctionPointer]属性来声明调用约定。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM