3

我有锯齿状数组,我需要将其传递给外部方法。

[DllImport(...)]
private static extern int NativeMethod(IntPtr[] ptrArray);

...

fixed (ulong* ptr = array[0])
{
    for (int i = 0; i < array.Length; i++)
    {
        fixed (ulong* p = &array[i][0])
        {
            ptrArray[i] = new IntPtr(p);
        }
    }

    NativeMethod(ptrArray);
}

问题是 ptr 未使用并且由于编译而被删除。比根据它的固定语句也被删除。因此,GC 会以 ptrArray 元素变为无效的方式移动数组。

将锯齿状数组作为指向本机方法的一维指针数组传递的最佳方法是什么?

更新:

这是 NativeMethod 的 C++ 代码:

NativeClass::NativeMethod(const int* array)
4

2 回答 2

3

您的问题在于您需要修复数组,因为这是您正在使用的数组。您可以固定阵列,以便 GC 不收集它:

 GCHandle h = GCHandle.Alloc(array, GCHandleType.Pinned);

更新

正如您正确指出的那样,数组中的每个数组也需要固定。

于 2010-10-27T12:25:53.260 回答
0

我已经能够通过外部 Pinvoke 方法将 C# 锯齿状数组传递给 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 部分,我会得到一个参数异常“对象包含非原始或非 blittable 数据”。那么是否可以固定 jaggedArray 并且真的需要它吗?(我隐约记得,如果不再使用,释放模式下的 GC 可能会在方法中重新收集内存。)我认为,尽管将 jaggedArray 转换为类字段变量,但从 GC 的角度来看会使其安全。

于 2011-10-14T09:05:39.670 回答