Исправлено заявление с зазубренным массивом
-
26-09-2019 - |
Вопрос
Я имею зазубренный массив, который мне нужно перейти к внешнему методу.
[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 становятся недействительными.
Какой лучший способ пропустить зазубренные массивы как одномерные массивы указателей на нативные методы?
Обновлять:
Вот код C ++ для NatiVeMethod:
NativeClass::NativeMethod(const int* array)
Решение
Ваша проблема заключается в том, что вам нужен массив, который будет исправлен, поскольку это тот, который вы используете. Вы можете установить массив, чтобы GC не собирал его:
GCHandle h = GCHandle.Alloc(array, GCHandleType.Pinned);
ОБНОВИТЬ
Как вы правильно указали, каждый массив внутри массива также нуждается в закреплении.
Другие советы
Я смог пройти C # зубчатый массив C ++ через внешний метод PINVOKE без использования небезопасного C # Code, как в образце кода ниже. Но у меня все еще есть проблемы, касающиеся 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];
}
Если бы я был, чтобы вотворить часть основной части, я получаю аргумент исключения «Объект содержит не примитивные или несыраемые данные». Так можно закрепить Jaggedarray и это действительно нужно? (Мне смутно напомни, что GC в режиме выпуска может вспоминать память уже в методах, если он больше не используется.) Думаю, хотя это поворачивая Jaggedarray в переменную поля класса, вместо этого сделает его безопасным от перспективы GC.