Подтвердить что ты не робот

С#: Как передать значение 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, и никакое действие, которое я пробовал, исправляет это.

Любые предложения?

4b9b3361

Ответ 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.