c # — Являются ли атрибуты P / Invoke [In, Out] необязательными для маршалинга массивов?

Предположим, что есть собственная функция с интерфейсом pure-C, подобная следующей, экспортированная из собственной DLL:

// NativeDll.cpp

extern "C" void __stdcall FillArray(
int fillValue,
int count,
int* data)
{
// Assume parameters are OK...

// Fill the array
for (int i = 0; i < count; i++)
{
data[i] = fillValue;
}
}

Следующий P / Invoke работает нормально (протестировано с VS2010 SP1):

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)]
public static extern void FillArray(
int fillValue,
int count,
[In, Out] int[] data
);

а также этот P / Invoke, такой же, как указано выше, но без [In, Out] атрибуты:

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)]
public static extern void FillArray(
int fillValue,
int count,
int[] data
);

Итак, это те, [In, Out] атрибуты необязательный для маршалинга массивов?
Какова их цель, если таковая имеется?
Можно ли их опускать в наших декларациях P / Invoke?

10

Решение

Нет, они не именно так необязательный. Это просто происходит случайно. Это, однако, очень распространенная авария. Это работает, потому что массив на самом деле не маршалируется. Маршаллер pinvoke видит, что массив C # уже совместим с собственным массивом, поэтому пропускает шаг для создания его копии. Он просто прикрепляет массив и передает указатель на нативный код.

Это, конечно, очень эффективно, и вы неизбежно получите результаты обратно, потому что нативный код напрямую записывает элементы массива. Таким образом, ни атрибуты [In], ни [Out] не имеют значения.

Это становится намного мрачнее, если тип элемента массива не так прост. Нелегко определить тип элемента, который является структурой или типом класса, который не является легковесным, или чей макет не соответствует после маршалинга, поэтому маршаллер pinvoke имеет сделать копию массива. Особенно несовместимость макета может быть очень трудно идентифицировать, потому что управляемый макет не обнаруживаем. И может меняться в зависимости от используемого джиттера. Он может работать в x86, но не в x64, например, довольно неприятно, когда выбран AnyCPU. Получение его, чтобы скопировать измененную копию обратно в массив C # делает требуют [Out].

Не уверен, что посоветовать, кроме того, что никто никогда не был уволен за то, что был явным в своих заявлениях. Возможно, вы всегда должны быть явными, когда тип элемента массива не прост, поэтому вы никогда не попадете в аварию.

20

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector