固定长度的语句与不规则数组

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)

你的本地方法长什么样子?它所接受的真实参数是什么? - A_Nabelsi
已更新 - 添加了C++代码 - levanovd
C++的声明不是用于锯齿数组,那需要一个int **参数。很难帮助你。 - Hans Passant
当然不是。我需要进行一些转换。 - levanovd
2个回答

3

你遇到的问题是需要固定数组,因为你正在使用它。你可以将数组钉住,这样垃圾回收器就不会收集它:

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

更新

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


你说得对,我在寻找Pinned但是找不到。 - Aliostad
现在你只需要将 h.AddrOfPinnedObject() 传递给本地方法即可。 - A_Nabelsi
谢谢!你的想法非常有帮助。我想补充的是,你的代码会产生异常,因为数组是数组而不是基本类型的数组。你应该固定(然后 .Free()!)每个数组[i],而不是数组本身。 - levanovd
你说得对,为了完整起见,我会添加这个注释。 - Aliostad

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部分,我会得到一个参数异常"Object contains non-primitive or non-blittable data"。那么是否有可能固定jaggedArray并且是否真的需要呢?(我模糊地记得,在发布模式下的GC可能已经回收了不再使用的方法内存。)但我认为,将jaggedArray转换为类字段变量,则可以从GC角度安全处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接