2010-10-27 2 views
3

У меня есть массив jagged, который мне нужно передать внешнему методу.Фиксированный оператор с неровным массивом

[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 становятся недействительными.

Каков наилучший способ передачи зубчатых массивов в виде одномерных массивов указателей на собственные методы?

Update:

Вот код C++ для NativeMethod:

NativeClass::NativeMethod(const int* array) 
+0

Каков ваш собственный метод, который выглядит как реальный параметр? –

+0

обновленный - добавлен код C++ – levanovd

+0

Объявление C++ является * not * для массива с зазубринами, для которого требуется аргумент int **. Трудно вам помочь. –

ответ

3

Ваша проблема связана с тем, что вам нужно массив быть фиксированным, так что это один вы используете. Вы можете прикрепить массив, так что GC не собирает его:

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

UPDATE

Как вы правильно отметили, каждый массив внутри массива нуждается пиннинга, а также.

+0

Но он все равно может переместить его. – levanovd

+0

Вы правы, я искал Pinned, но не смог его найти. – Aliostad

+0

Теперь вам нужно просто передать h.AddrOfPinnedObject() в собственный метод. –

0

Я смог передать массив C# с jagged на C++ с помощью внешнего метода Pinvoke, не используя небезопасный код 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.