web-dev-qa-db-ja.com

string.Formatがnull値を処理する方法

次のコードでは、なぜ2つのstring.Format呼び出しは同じように動作しませんか?最初の例外では例外はスローされませんが、2番目の例外ではArgumentNullExceptionがスローされます。

static void Main(string[] args)
{
    Exception e = null;
    string msgOne = string.Format("An exception occurred: {0}", e);
    string msgTwo = string.Format("Another exception occurred: {0}", null);
}

誰かが2つの違いを理解するのを助けてくれますか?

61
Martin

私はここで推測していますが、それはあなたがヒットしているオーバーロードされたコールの違いのようです。 _String.Format_ には複数のオーバーロードがありますが、それはちょうどあなたがヒットしているものです。

最初の例では、 String.Format(string,object) を押すのが理にかなっています。

2番目の例では、nullを指定することで String.Format(string,params object[]) にヒットする可能性が高く、ドキュメントによると、次の場合にArgumentNullExceptionが発生します。

formatまたはargsがヌルです。

.NET4を実行している場合は、名前付きパラメーターを使用してみてください。

_String.Format("Another exception occured: {0}", arg0: null);
_

なぜ_params object[]_オーバーロードにヒットするのですか?おそらくnullはオブジェクトではなく、paramsが機能する方法は、各値をeither渡すことができるためです呼び出しの新しいオブジェクトとしてまたは値の配列を渡します。つまり、以下は 同じものの1つ です。

_String.Format("Hello, {0}! Today is {1}.", "World", "Sunny");
String.Format("Hello, {0}! Today is {1}.", new Object[]{ "World", "Sunny" })
_

したがって、ステートメント呼び出しを次の行に沿って何かに翻訳しています:

_String format = "Another exception occured: {0}";
Object[] args = null;
String.Format(format, args); // throw new ArgumentNullException();
_
47
Brad Christie

最初の例では、Format(String, Object)をヒットしています。これは、逆アセンブルすると次のようになります。

_ public static string Format(string format, object arg0)
 {
    return Format(null, format, new object[] { arg0 });
 }
_

その周りの_new object[]_に注意してください。

2番目の方法は、明らかにFormat(string, object[])の使用法です。少なくとも、同じテストを実行するときに呼び出されます。逆アセンブルされ、次のようになります。

_ public static string Format(string format, params object[] args)
 {
     return Format(null, format, args);
 }
_

したがって、これらはすべてFormat(IFormatProvider, string, object[])に集中します。クール、最初の数行を見てみましょう。

_public static string Format(IFormatProvider provider, string format, params object[] args)
{
    if ((format == null) || (args == null))
    {
        throw new ArgumentNullException((format == null) ? "format" : "args");
    }
...
}
_

...うーん、そこにあなたの問題があります!最初の呼び出しは、新しい配列でラップするため、nullではありません。呼び出しているFormat()の特定のインスタンスのために、明示的にnullを渡しても、そうすることはありません。

11
tmesser

補間された文字列($ ""、フォーマットの別の方法)を使用する場合、nullは無視され、スキップされます。そう

string nullString = null;
Console.WriteLine($"This is a '{nullString}' in a string");

「これは文字列の ''です」を生成します。もちろん、nullの場合は、null合体演算子を使用して必要な出力を生成できます。

string nullString = null;
Console.WriteLine($"This is a '{nullString ?? "nothing"}' in a string");
2
Gerard

最初の呼び出しはFormat(object)の呼び出しとして解決され、2番目の呼び出しはFormat(object [])の呼び出しとして解決されます。 Nullパラメーターは、これらの異なるオーバーロードによって異なる方法で処理されます。

過負荷の解決については こちら で説明しています。関連する部分は、Formatの2番目の呼び出しで、Format(params object [])のオーバーロードがFormat(object [])に展開されることです。これはFormat(object)より優先されます。リテラルnullはobject []とオブジェクトの両方ですが、object []はより具体的であるため、選択されます。

2
RossFabricant