2009-04-10 10 views
26

Ich habe die folgende Funktion bekommt:C#: Wie wird NULL an eine Funktion übergeben, die einen Ref erwartet?

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

Welche Ich mag würde wie folgt nennen:

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

Leider kann ich nicht null in einem Feld übergeben, die ref Mapping geben und keine Besetzung I erfordert habe versucht das behebt.

Irgendwelche Vorschläge?

+0

Mögliche Duplikate von [Wie behandle ich optionale C++ - DLL-Struktur Argumente in C#] (https://stackoverflow.com/questions/47997942/how-doi-i-handle-optional-c-dll-struct-arguments- in-c-sharp) – River

Antwort

30

ich das Mapping gehe davon ist eine Struktur? Wenn ja, können Sie zwei Versionen des FILES_GetMemoryMapping()-Prototyps mit verschiedenen Signaturen haben. Für die zweite Überlastung, wo Sie passieren null wollen, wird der Parameter machen eine IntPtr und 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); 

Anruf verwenden, zB:

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

Wenn Mapping tatsächlich eine Klasse anstelle einer Struktur ist, so stellen Sie die Wert auf null, bevor es übergeben wird.

+0

Funktioniert wie ein Charme! – Nick

+3

Und was schlagen Sie vor, wenn Sie eine Funktion mit 8 Zeiger auf Strukturen haben und jeder von ihnen null sein kann? Sollte ich 256 Überladungen schreiben? Mit Nullable-Werttyp funktioniert Dummy-Variable? – Calmarius

+0

@Calmarius Warum nicht einfach eine Definition schreiben, die alle 'ref ' durch 'IntPtr' ersetzt? Ja, es ist weniger sicher, aber es scheint, wenn Sie mit P/Invoke umgehen, ist die Sicherheit des Codes schon nicht der Punkt. – SerG

6

Eine Möglichkeit ist es, eine Dummy-Variable zu erstellen, weisen sie null, und übergeben, daß in.

2
Mapping oMapping = null; 

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

Mapping ist eigentlich eine Struktur, so dass ich es nicht auf Null setzen kann. – Nick

+0

@Nick, siehe meine Antwort für den Strukturfall – JaredPar

+3

Ich denke, das vermisst den Punkt. Manchmal haben Funktionen Ref-Parameter, die Sie nicht interessieren. Unnötige Variablen zu definieren, verstopft Code und ist ärgerlich. –

23

Der Grund, warum Sie null nicht bestehen können, liegt daran, dass ein ref-Parameter vom C# -Compiler speziell behandelt wird. Jeder Parameter ref muss eine Referenz sein, die an die Funktion übergeben werden kann, die Sie aufrufen. Da Sie null übergeben möchten, verweigert der Compiler dies, da Sie keine Referenz angeben, die die Funktion erwartet.

Ihre einzige echte Option wäre, eine lokale Variable zu erstellen, setzen Sie es auf null, und übergeben Sie das in. Der Compiler wird Ihnen nicht erlauben, viel mehr als das zu tun.

1

Während @ JaredPar answer das ist zweifellos die richtige Antwort gibt es andere Antwort: unsafe Code und Zeiger:

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

Das sieht wie es zur Laufzeit fehlschlagen sollte, aber es doesn‘ t, weil die ref und die * sich gegenseitig auslöschen, und der resultierende Wert von ref *nullMapping ist der Nullzeiger, der FILES_GetMemoryMapping() für diesen Parameter erhalten wird.

Dies ist wahrscheinlich keine gute Idee, aber es ist möglich.