Ключевые слова `in, out, ref` vs Attributes` [In], [Out], [In, Out] ` - PullRequest
2 голосов
/ 12 мая 2019

Я знаю, что первый набор ключевых слов in, out, ref может использоваться во всех функциях C #, а второй набор атрибутов [In], [Out], [In, Out] предназначен для маршаллера.

Я не уверен, имеют ли они в виду одно и то же при использовании в объявлении функции нативного кода.Например, эквивалентны ли следующие два объявления?

[DllImport("xxx.dll")]
void FillArray1(ref int[] arr, in int length);

[DllImport("xxx.dll")]
void FillArray2([In, Out] int[] arr, [In] int length);

Есть ли случаи, когда два набора не эквивалентны?

1 Ответ

1 голос
/ 12 мая 2019

Они не эквивалентны.

Для ref int[] arr атрибуты [In, Out] по умолчанию будут применяться автоматически, но они по-прежнему не совпадают с [In, Out] int[] arr.

ref int[] arr - двойное косвенное обращение (ссылочный тип, передаваемый по ссылке). Используйте это, если нативная сторона определена примерно так: int32_t** arr. Это позволяет заменить не только элементы, но и весь экземпляр массива.

С другой стороны, [In, Out] int[] arr - это простая ссылка, передаваемая по значению. Используйте это, если нативная сторона также использует одиночное косвенное обращение, например. int32_t* arr. Обычно в C #, если вы передаете массив по значению (который является ссылочным типом), вызываемый метод может заменить элементы, которые будут отражены со стороны вызывающей стороны. Однако маршалинг P / Invoke работает немного иначе :

По умолчанию ссылочные типы (классы, массивы, строки и интерфейсы), передаваемые по значению, маршалируются как In параметры из соображений производительности. Вы не увидите изменений в этих типах, если не примените InAttribute и OutAttribute (или просто OutAttribute) к параметру метода.

Таким образом, нативная сторона получает правильный указатель независимо от указания атрибута Out. Здесь необходимо указать [Out] для маршалера, чтобы он не пропустил сеанс обратного копирования в управляемую память.

Аналогично, in int length будет передавать ссылку на целое число и не совпадает с [In] int length, который передает параметр просто по значению. [In] может быть опущено, так как в этом случае это стандартное поведение маршалинга.

...