2009-04-10 21 views
26

Tengo la siguiente función:C#: ¿Cómo pasar null a una función esperando una referencia?

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

cual me gustaría llamar así:

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

Por desgracia, no puedo dejar pasar null en un campo que requiere escribir ref Mapping y ningún molde I He intentado arreglar esto.

¿Alguna sugerencia?

+0

Posible duplicado de [¿Cómo manejo los argumentos opcionales de estructura dll de C++ en C#] (https://stackoverflow.com/questions/47997942/how-do-i-handle-optional-c-dll-struct-arguments- in-c-sharp) – River

Respuesta

30

Estoy asumiendo que Mapping es una estructura? De ser así, puede tener dos versiones del prototipo FILES_GetMemoryMapping() con diferentes firmas. Para la segunda sobrecarga en la que desea pasar null, hacen que el parámetro un IntPtr y utilizar 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); 

ejemplo Llamar:

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

Si Mapping es en realidad una clase en lugar de una estructura, acaba de establecer la valor para nulo antes de pasarlo hacia abajo.

+0

¡Funciona como un encanto! – Nick

+3

¿Y qué sugieres si tienes una función con 8 punteros a estructuras y cualquiera de ellas puede ser nula? ¿Debo escribir 256 sobrecargas? Usando el tipo de valor nulo, la variable ficticia funciona? – Calmarius

+0

@Calmarius ¿Por qué no escribir una definición reemplazar todo '' ref con 'IntPtr'? Sí, es menos seguro, pero parece que si trabajas con P/Invoke, la seguridad del código ya no es el objetivo. – SerG

6

Una forma es crear una variable ficticia, asignarle nula, y pasar de que en.

2
Mapping oMapping = null; 

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

La asignación es en realidad una estructura, por lo que no puedo establecer que sea nula. – Nick

+0

@Nick, ver mi respuesta para el caso de estructura – JaredPar

+3

Creo que esto no tiene sentido. A veces las funciones tienen parámetros de referencia que no te importan. Tener que definir variables inutiles desordena el código y es molesto. –

23

La razón por la que no se puede pasar null es porque un parámetro ref recibe un tratamiento especial por parte del compilador C#. Cualquier parámetro ref debe ser una referencia que se pueda pasar a la función a la que llama. Como quiera pasar null, el compilador se niega a permitir esto ya que no está proporcionando una referencia que la función espera tener.

Su única opción real sería crear una variable local, configurarla en null, y pasarla. El compilador no le permitirá hacer mucho más que eso.

1

Mientras @ de answer JaredPar es sin duda el correcta respuesta, no es otra respuesta: unsafe código y punteros:

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

Eso ve como debe fallar en tiempo de ejecución, pero doesn' t, porque ref y * se cancelan mutuamente, y el valor resultante de ref *nullMapping es el puntero nulo, que es lo que FILES_GetMemoryMapping() recibirá para ese parámetro.

Esto no es probablemente una buena idea, pero es posible .

Cuestiones relacionadas