2016-01-25 43 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

相關問題