C #: как передать null в функцию, ожидающую ref? - PullRequest
28 голосов
/ 10 апреля 2009

У меня есть следующая функция:

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, и ни одно приведение, которое я пробовал, исправляет это.

Есть предложения?

Ответы [ 7 ]

30 голосов
/ 10 апреля 2009

Я предполагаю, что картирование - это структура? Если это так, вы можете иметь две версии прототипа FILES_GetMemoryMapping() с разными подписями. Для второй перегрузки, в которой вы хотите передать null, задайте для параметра 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);

Если Mapping на самом деле является классом, а не структурой, просто установите значение в null, прежде чем передавать его вниз.

27 голосов
/ 10 апреля 2009

Причина, по которой вы не можете передать null, заключается в том, что параметру ref назначена специальная обработка компилятором C #. Любой параметр ref должен быть ссылкой, которую можно передать вызываемой функции. Поскольку вы хотите передать null, компилятор отказывается разрешить это, поскольку вы не предоставляете ссылку, которую ожидает функция.

Ваша единственная реальная возможность - создать локальную переменную, установить ее на null и передать ее. Компилятор не позволит вам сделать намного больше.

9 голосов
/ 10 апреля 2009

Один из способов - создать фиктивную переменную, присвоить ей значение null и передать ее.

4 голосов
/ 10 апреля 2009
Mapping oMapping = null;

FILES_GetMemoryMapping(MapFile, out size, MapName, out PacketSize, ref oMapping, out PagePerSector);
1 голос
/ 07 июня 2019

Нуль теперь можно разрешить с использованием языка C # 7.2 или выше. Просто замените ref в параметре вашей функции следующим образом ...

void MyFunc(ref Object obj) { ... }

до ...

void MyFunc(in Object obj) { ... }

Это позволит вам ввести null в качестве значения параметра при вызове функции в вашем приложении. Он работает одинаково для объектов и нативных типов и синтаксически эквивалентен ref readonly.

1 голос
/ 22 октября 2015

Хотя @ 1001 * ответ @ JaredPar , несомненно, является правильным ответом, существует другой ответ: unsafe код и указатели:

unsafe {
    Mapping* nullMapping = null;
    FILES_GetMemoryMapping(
            MapFile,
            out size,
            MapName,
            out PacketSize,
            ref *nullMapping,    // wat?
            out PagePerSector);
}

То, что выглядит , как будто оно должно завершиться с ошибкой во время выполнения, но это не так, потому что ref и * отменяют друг друга, а результирующее значение ref *nullMapping равно нулю указатель, который FILES_GetMemoryMapping() получит для этого параметра.

Это, вероятно, не очень хорошая идея , но это возможно .

0 голосов
/ 22 июня 2018

Возможно, это не совсем идеальный ответ, но если вам нужно передать значение null в качестве параметра при вызове функции, рассмотрите возможность перегрузки этой функции, которая пропускает формальный параметр для переменной, которую вы пытаетесь установить в null.

Например, допустим, у вас есть функция, которая выглядит следующим образом:

public void MyFunction(string x, int y, ref string z) {...};

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

public void MyFunction(string x, int y) {...};

Этот подход не подойдет всем, но это еще одно возможное решение.

...