以下のコードサンプルのように、安全でないC#コードを使用せずに、外部のPinvokeメソッドを介してC#ジャグ配列をC++に渡すことができました。しかし、デバッグモード以外のGCが望ましくない副作用を引き起こすことについては、まだ懸念があります。これがテストコードの一部です(デバッグモードで動作します):
[Test, Ignore]
public void Test_JaggedArrayPInvoke()
{
var jaggedArray = new int[3][];
jaggedArray[0] = new int[1] { 9 };
jaggedArray[1] = new int[4] { 1, 2, 3, 8 };
jaggedArray[2] = new int[2] { 1, 2 };
//GCHandle mainHandle = GCHandle.Alloc(jaggedArray, GCHandleType.Pinned); //This does not work
var pinnedHandles = new GCHandle[3];
var jaggedArrayPtrs = new IntPtr[3];
for (int i = 0; i < 3; i++)
{
pinnedHandles[i] = GCHandle.Alloc(jaggedArray[i], GCHandleType.Pinned);
jaggedArrayPtrs[i] = pinnedHandles[i].AddrOfPinnedObject();
}
var result = JaggedArrayPInvoke_TEST(jaggedArrayPtrs);
Console.WriteLine(result); //returns 8 as it should.
//mainHandle.Free();
for (int i = 0; i < 3; i++)
{
pinnedHandles[i].Free();
}
}
//The C++ test method:
extern "C" __declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray);
__declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray)
{
return jaggedArray[1][3];
}
mainHandle部分のコメントを解除すると、「オブジェクトに非プリミティブまたは非ブリット可能なデータが含まれています」という引数例外が発生します。では、jaggedArrayを固定することは可能ですか?それは本当に必要ですか?(リリースモードのGCは、もう使用されていない場合、メソッド内のメモリを再収集する可能性があることを漠然と思い出します。)代わりに、jaggedArrayをクラスフィールド変数に変換すると、GCの観点から安全になると思います。