web-dev-qa-db-ja.com

C#:参照が必要な関数にnullを渡す方法は?

私は次の機能を持っています:

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

私はこれをこのように呼びたいです:

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

残念ながら、タイプref Mappingを必要とするフィールドにnullを渡すことはできません。これを修正したキャストはありません。

助言がありますか?

34
Nick

マッピングは構造であると想定していますか?もしそうなら、異なるシグネチャを持つFILES_GetMemoryMapping()プロトタイプの2つのバージョンを持つことができます。 nullを渡す2番目のオーバーロードでは、パラメーターをIntPtrにして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);

呼び出し例:

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

マッピングが実際には構造ではなくクラスである場合は、値をnullに設定してから渡します。

32
JaredPar

nullを渡せない理由は、refパラメーターがC#コンパイラーによって特別に処理されるためです。 refパラメータはすべて、呼び出す関数に渡すことができる参照である必要があります。 nullを渡したいので、関数が期待する参照を提供していないため、コンパイラーはこれを許可しません。

あなたの唯一の本当の選択肢は、ローカル変数を作成し、それをnullに設定して渡すことです。コンパイラーはそれ以上のことを許可しません。

34
Andrew Hare

1つの方法は、ダミー変数を作成してnullを割り当て、それを渡すことです。

10
Erich Mirabal
Mapping oMapping = null;

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

C#言語7.2以降を使用してnullを許可できるようになりました。単純に、関数パラメーターのrefを次のように置き換えます...

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

に...

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

これにより、アプリケーションで関数を呼び出すときに、nullをパラメーター値として渡すことができます。オブジェクトとネイティブタイプで同じように機能し、ref readonlyと構文的に同等です。

2
Jim Fell

@JaredParの answer は間違いなく正しい回答ですが、another回答:unsafeコードとポインタ:

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

そのは実行時に失敗するように見えますが、実際には失敗しません。refと_*_はそれぞれキャンセルするためその他、および_ref *nullMapping_の結果の値はnullポインターです。これはFILES_GetMemoryMapping()がそのパラメーターに対して受け取るものです。

これはおそらく良い考えではありませんが、可能です

2
jonp

おそらくそれは理想的な答えではないかもしれませんが、関数を呼び出すときにパラメーターとしてnullを渡す必要がある場合は、nullに設定しようとしている変数の仮パラメーターを省略する関数のオーバーロードを作成することを検討してください。

たとえば、次のような関数があるとします。

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

パラメータzにnullを渡せるようにしたい。代わりに、次のような新しいMyFunctionオーバーロードを作成してみてください。

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

このアプローチはすべての人のニーズに合うわけではありませんが、別の可能な解決策です。

0
Jazimov