Nick
Nick

Reputation: 2959

C#: How to pass null to a function expecting a ref?

I've got the following function:

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);

Which I would like to call like this:

FILES_GetMemoryMapping(MapFile, out size, MapName,
    out PacketSize, null, out PagePerSector);

Unfortunately, I cannot pass null in a field that requires type ref Mapping and no cast I've tried fixes this.

Any suggestions?

Upvotes: 55

Views: 63905

Answers (10)

Marcin Rybak
Marcin Rybak

Reputation: 11

System.Runtime.CompilerServices.Unsafe:

ref Unsafe.NullRef<Mapping>()

This doesn't require enabling unsafe code in the project.

Upvotes: 0

Alpha Anar
Alpha Anar

Reputation: 39

You can get a null ref using System.Runtime.CompilerServices.Unsafe class.

ref Unsafe.AsRef<Mapping>(null)

Upvotes: 3

Redplcs
Redplcs

Reputation: 308

bro, then use pointers like in c

public static extern unsafe uint FILES_GetMemoryMapping(
    [MarshalAs(UnmanagedType.LPStr)] string pPathFile,
    out ushort Size,
    [MarshalAs(UnmanagedType.LPStr)] string MapName,
    out ushort PacketSize,
    Mapping* oMapping,
    out byte PagesPerSector);

// somewhere in code
unsafe {
    uint result = FILES_GetMemoryMapping("path", out ushort size, "map", out ushort packetSize, null, out byte pages);
}

Upvotes: 1

Jim Fell
Jim Fell

Reputation: 14256

Null can now be permitted using C# language 7.2 or greater. Simply replace the ref in your function parameter like so...

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

to...

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

This will let you pass in null as a parameter value when calling the function in your application. It works the same for objects and native types and is syntactically equivalent to ref readonly.

Upvotes: 3

Jazimov
Jazimov

Reputation: 13292

Perhaps its not exactly the ideal answer, but if you need to pass null as a parameter when calling a function, consider making an overload of that function that omits the formal parameter for the variable you're trying to set to null.

For example, let's say you have a function that looks like this:

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

You want to be able to pass null for parameter z. Try instead creating a new MyFunction overload that looks something like this:

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

This approach won't suit everyone's needs, but it's another possible solution.

Upvotes: 0

jonp
jonp

Reputation: 13600

While @JaredPar's answer is undoubtedly the correct answer, there is another answer: unsafe code and pointers:

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

That looks like it should fail at runtime, but it doesn't, because the ref and the * cancel each other out, and the resulting value of ref *nullMapping is the null pointer, which is what FILES_GetMemoryMapping() will receive for that parameter.

This is probably not a good idea, but it's possible.

Upvotes: 5

JaredPar
JaredPar

Reputation: 754705

I'm assuming that Mapping is a structure? If so you can have two versions of the FILES_GetMemoryMapping() prototype with different signatures. For the second overload where you want to pass null, make the parameter an IntPtr and use 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);

Call example:

FILES_GetMemoryMapping(MapFile, out size, MapName,
   out PacketSize, IntPtr.Zero, out PagePerSector);

If Mapping is actually a class instead of a structure, just set the value to null before passing it down.

Upvotes: 34

Andrew Hare
Andrew Hare

Reputation: 351516

The reason you cannot pass null is because a ref parameter is given special treatment by the C# compiler. Any ref parameter must be a reference that can be passed to the function you are calling. Since you want to pass null the compiler is refusing to allow this since you are not providing a reference that the function is expecting to have.

Your only real option would be to create a local variable, set it to null, and pass that in. The compiler will not allow you to do much more than that.

Upvotes: 51

Chris Doggett
Chris Doggett

Reputation: 20757

Mapping oMapping = null;

FILES_GetMemoryMapping(MapFile, out size, MapName, out PacketSize, ref oMapping, out PagePerSector);

Upvotes: 4

Erich Mirabal
Erich Mirabal

Reputation: 10038

One way is to create a dummy variable, assign it null, and pass that in.

Upvotes: 11

Related Questions