web-dev-qa-db-fra.com

C #: Comment passer null à une fonction attendant une référence?

J'ai la fonction suivante:

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 j'aimerais appeler comme ça:

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

Malheureusement, je ne peux pas passer null dans un champ nécessitant le type ref Mapping et aucune conversion n'a été essayée.

Aucune suggestion?

28
Nick

Je suppose que la cartographie est une structure? Si c'est le cas, vous pouvez avoir deux versions du prototype FILES_GetMemoryMapping() avec des signatures différentes. Pour la deuxième surcharge où vous souhaitez passer null, définissez le paramètre sur IntPtr et utilisez 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:

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

Si Mapping est en réalité une classe au lieu d'une structure, définissez simplement la valeur sur null avant de la transmettre.

30
JaredPar

La raison pour laquelle vous ne pouvez pas transmettre null est qu’un paramètre ref reçoit un traitement spécial du 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 permettre cela car vous ne fournissez pas une référence que la fonction s'attend à avoir.

Votre seule véritable option serait de créer une variable locale, de la définir sur null et de la transmettre. Le compilateur ne vous permettra pas de faire beaucoup plus que cela.

25
Andrew Hare

Une solution consiste à créer une variable muette, à l’assigner à null et à la transmettre.

9
Erich Mirabal
Mapping oMapping = null;

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

Tandis que answer de @ JaredPar est sans aucun doute le correct réponse, il y a un autre réponse: code unsafe et pointeurs:

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

Cela semble comme si cela devait échouer à l'exécution, mais ce n'est pas le cas, car ref et * s'annulent, et la valeur résultante de ref *nullMapping est le pointeur null, qui correspond à ce que FILES_GetMemoryMapping() recevra pour ce paramètre.

Ce n'est probablement pas une bonne idée , mais c'est possible .

1
jonp

Ce n'est peut-être pas la réponse idéale, mais si vous devez passer à null en tant que paramètre lorsque vous appelez une fonction, envisagez de surcharger celle-ci en surchargeant le paramètre formel de la variable que vous essayez de définir sur null. 

Par exemple, disons que vous avez une fonction qui ressemble à ceci:

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

Vous voulez pouvoir passer null pour le paramètre z. Essayez plutôt de créer une nouvelle surcharge MyFunction qui ressemble à ceci:

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

Cette approche ne convient pas aux besoins de tous, mais c'est une autre solution possible. 

0
Jazimov