2009-04-10 5 views
26

J'ai la fonction suivante:C#: Comment passer null à une fonction attend une ref?

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

Ce que je voudrais appeler comme ceci:

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

Malheureusement, je ne peux pas passer null dans un domaine qui exige de type ref Mapping et ne jetterai I J'ai essayé de réparer ça.

Des suggestions?

+0

Copie possible de [Comment gérer les arguments facultatifs de struct dll C++ en C#] (https://stackoverflow.com/questions/47997942/how-do-i-handle-optional-c-dll-struct-arguments- in-c-sharp) – River

Répondre

30

Je suppose que la cartographie est une structure? Si oui, vous pouvez avoir deux versions du prototype FILES_GetMemoryMapping() avec des signatures différentes. Pour la deuxième surcharge où vous voulez passer null, faire le paramètre un IntPtr et utiliser 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); 

Exemple d'appel: à la place

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

Si le mappage est en fait une classe d'une structure, vient de mettre la valeur à null avant de le transmettre.

+0

Fonctionne comme un charme! – Nick

+3

Et que suggérez-vous si vous avez une fonction avec 8 pointeur sur les structs et l'un d'eux peut être nul? Dois-je écrire 256 surcharges? L'utilisation du type de valeur Null va-t-elle faire fonctionner la variable dummy? – Calmarius

+0

@Calmarius Pourquoi ne pas simplement écrire une définition en remplaçant tous 'ref ' par 'IntPtr'? Oui, c'est moins sûr, mais il semble que si vous faites affaire avec P/Invoke, la sécurité du code n'est déjà pas le point. – SerG

6

Une façon est de créer une variable fictive, assigner nulle, et passer que.

2
Mapping oMapping = null; 

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

Le mappage est en fait une structure, donc je ne peux pas le mettre à null. – Nick

+0

@Nick, voir ma réponse pour le cas de la structure – JaredPar

+3

Je pense que cela manque le point. Parfois, les fonctions ont des paramètres ref qui ne vous intéressent pas. Devoir définir des variables inutiles encode le code et est agaçant. –

23

La raison pour laquelle vous ne pouvez pas passer le null est qu'un paramètre ref est traité de manière particulière par le compilateur C#. Tout paramètre ref doit être une référence pouvant être transmise à la fonction que vous appelez. Puisque vous voulez passer null le compilateur refuse de le permettre puisque vous ne fournissez pas de référence que la fonction s'attend à avoir.

Votre seule option réelle serait de créer une variable locale, réglez-la sur null, et transmettez-la. Le compilateur ne vous permettra pas de faire beaucoup plus que cela.

1

Alors que @ JaredPar de answer est sans aucun doute la bonneréponse, il y a une autre réponse: unsafe code et pointeurs:

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

Ce semble comme il devrait échouer lors de l'exécution, mais il n » t, car le ref et le * s'annulent mutuellement et la valeur résultante de ref *nullMapping est le pointeur nul, ce que recevra FILES_GetMemoryMapping() pour ce paramètre. Ceci n'est probablement pas une bonne idée, mais c'est possible

Questions connexes