文字列がnullに初期化されてから、本番環境で何かが追加される例を見て驚いた。悪臭がするだけです。
私はそれがnullオブジェクト例外をスローするだろうと確信していましたが、この大幅に削減された例も機能します:
string sample = null;
sample += "test";
// sample equals "test"
* 私が見つけた元のコードは文字列プロパティをnullに設定し、それを他の場所に追加するため、コンパイル時にnullを最適化するコンパイラを含む回答は無関係です。
これがエラーなしで機能する理由を誰かが説明できますか?
Leppieの回答に基づいて、リフレクターを使用してstring.Concatの内部を確認しました。その変換が行われる理由は本当に明らかです(まったく魔法ではありません)。
public static string Concat(string str0, string str1)
{
if (IsNullOrEmpty(str0))
{
if (IsNullOrEmpty(str1))
{
return Empty;
}
return str1;
}
if (IsNullOrEmpty(str1))
{
return str0;
}
int length = str0.Length;
string dest = FastAllocateString(length + str1.Length);
FillStringChecked(dest, 0, str0);
FillStringChecked(dest, length, str1);
return dest;
}
** 注:(Microsoftの.Netライブラリで)私が調査していた特定の実装は、C#標準およびほとんどの回答で提案されているように空の文字列に変換されませんが、いくつかのテストを使用してプロセス。最終結果はそれがした場合と同じですが、そこに行きます:)
文字列の+
演算子は、連結の前にnull
引数を空の文字列に変換するだけのstring.Concat
の省略形です。
更新:
String.Concatの一般化バージョン:
public static string Concat(params string[] values)
{
int num = 0;
if (values == null)
{
throw new ArgumentNullException("values");
}
string[] array = new string[values.Length];
for (int i = 0; i < values.Length; i++)
{
string text = values[i];
array[i] = ((text == null) ? string.Empty : text);
num += array[i].Length;
if (num < 0)
{
throw new OutOfMemoryException();
}
}
return string.ConcatArray(array, num);
}
関連する引用は ECMA-334 §14.7.4である必要があります:
文字列の連結:
string operator +(string x, string y); string operator +(string x, object y); string operator +(object x, string y);
バイナリ
+
演算子は、一方または両方のオペランドのタイプがstring
の場合に文字列連結を実行します。 文字列連結のオペランドがnull
の場合、空の文字列が置き換えられます。それ以外の場合、非文字列オペランドはその文字列に変換されますタイプToString
から継承された仮想object
メソッドを呼び出すことによる表現。ToString
がnull
を返す場合、空の文字列が置換されます。
なぜなら
文字列連結演算では、C#コンパイラはnull文字列を空の文字列と同様に扱いますが、元のnull文字列の値は変換しません。
From 方法:複数の文字列を連結する(C#プログラミングガイド)
二項+演算子は、一方または両方のオペランドが文字列型である場合に文字列連結を実行します。文字列連結のオペランドがnullの場合、空の文字列が置換されます。それ以外の場合、文字列以外の引数は、型オブジェクトから継承された仮想ToStringメソッドを呼び出すことにより、文字列表現に変換されます。 ToStringがnullを返す場合、空の文字列が置換されます。
From 加算演算子
これがあなたのコードがコンパイルされるものです
string sample = null;
sample += "test";
このILコードにコンパイルされます。
.entrypoint
// Code size 16 (0x10)
.maxstack 2
.locals init ([0] string sample)
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldstr "test"
IL_0009: call string [mscorlib]System.String::Concat(string,
string)
IL_000e: stloc.0
IL_000f: ret
そしてString.Concat
はNULL文字列を処理します。