С#: Как передать значение null функции, ожидающей ссылки?
У меня есть следующая функция:
public static extern uint FILES_GetMemoryMapping(
[MarshalAs(UnmanagedType.LPStr)] string pPathFile,
out ushort Size,
[MarshalAs(UnmanagedType.LPStr)] string MapName,
out ushort PacketSize,
ref Mapping oMapping,
out byte PagesPerSector);
Что я хотел бы назвать так:
FILES_GetMemoryMapping(MapFile, out size, MapName,
out PacketSize, null, out PagePerSector);
К сожалению, я не могу передать null
в поле, которое требует типа ref Mapping
, и никакое действие, которое я пробовал, исправляет это.
Любые предложения?
Ответы
Ответ 1
Я предполагаю, что Mapping является структурой? Если это так, вы можете иметь две версии прототипа FILES_GetMemoryMapping()
с разными сигнатурами. Для второй перегрузки, где вы хотите передать null
, введите параметр a IntPtr
и используйте IntPtr.Zero
public static extern uint FILES_GetMemoryMapping(
[MarshalAs(UnmanagedType.LPStr)] string pPathFile,
out ushort Size,
[MarshalAs(UnmanagedType.LPStr)] string MapName,
out ushort PacketSize,
IntPtr oMapping,
out byte PagesPerSector);
Пример вызова:
FILES_GetMemoryMapping(MapFile, out size, MapName,
out PacketSize, IntPtr.Zero, out PagePerSector);
Если отображение является фактически классом вместо структуры, просто установите значение null перед его передачей.
Ответ 2
Причина, по которой вы не можете пройти null
, заключается в том, что параметр ref
получает специальную обработку компилятором С#. Любой параметр ref
должен быть ссылкой, которая может быть передана функции, которую вы вызываете. Поскольку вы хотите передать null
, компилятор отказывается разрешать это, поскольку вы не предоставляете ссылку, которую ожидает функция.
Единственная реальная опция - создать локальную переменную, установить ее в null
и передать ее. Компилятор не позволит вам делать гораздо больше.
Ответ 3
Один из способов - создать фиктивную переменную, присвоить ей значение null и передать ее.
Ответ 4
Mapping oMapping = null;
FILES_GetMemoryMapping(MapFile, out size, MapName, out PacketSize, ref oMapping, out PagePerSector);
Ответ 5
Хотя @JaredPar answer, несомненно, правильный ответ, есть еще один ответ: unsafe
код и указатели:
unsafe {
Mapping* nullMapping = null;
FILES_GetMemoryMapping(
MapFile,
out size,
MapName,
out PacketSize,
ref *nullMapping, // wat?
out PagePerSector);
}
Похоже, что он не работает во время выполнения, но это не так, потому что ref
и *
отменяют друг друга, а итоговое значение ref *nullMapping
- это нулевой указатель, что означает FILES_GetMemoryMapping()
получит для этого параметра.
Это, вероятно, не очень хорошая идея, но это возможно.
Ответ 6
Возможно, это не совсем идеальный ответ, но если вам нужно передать значение null в качестве параметра при вызове функции, рассмотрите возможность перегрузки этой функции, которая пропускает формальный параметр для переменной, которую вы пытаетесь установить в null.
Например, допустим, у вас есть функция, которая выглядит следующим образом:
public void MyFunction(string x, int y, ref string z) {...};
Вы хотите быть в состоянии передать нуль для параметра z. Попробуйте вместо этого создать новую перегрузку MyFunction
которая выглядит примерно так:
public void MyFunction(string x, int y) {...};
Такой подход не подойдет всем, но это еще одно возможное решение.
Ответ 7
Нуль теперь может быть разрешен с использованием языка С# 7.2 или выше. Просто замените ref
в параметре вашей функции следующим образом...
void MyFunc(ref Object obj) { ... }
чтобы...
void MyFunc(in Object obj) { ... }
Это позволит вам передать значение null
в качестве значения параметра при вызове функции в вашем приложении. Он работает одинаково для объектов и нативных типов и синтаксически эквивалентен ref readonly
.