web-dev-qa-db-ja.com

C#ではnull文字列への追加はどのように機能しますか?

文字列が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#標準およびほとんどの回答で提案されているように空の文字列に変換されませんが、いくつかのテストを使用してプロセス。最終結果はそれがした場合と同じですが、そこに行きます:)

45
Gone Coding

文字列の+演算子は、連結の前に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);
}
47
leppie

関連する引用は 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メソッドを呼び出すことによる表現。 ToStringnullを返す場合、空の文字列が置換されます。

7
Rasmus Faber

なぜなら

文字列連結演算では、C#コンパイラはnull文字列を空の文字列と同様に扱いますが、元のnull文字列の値は変換しません。

From 方法:複数の文字列を連結する(C#プログラミングガイド)

二項+演算子は、一方または両方のオペランドが文字列型である場合に文字列連結を実行します。文字列連結のオペランドがnullの場合、空の文字列が置換されます。それ以外の場合、文字列以外の引数は、型オブジェクトから継承された仮想ToStringメソッドを呼び出すことにより、文字列表現に変換されます。 ToStringがnullを返す場合、空の文字列が置換されます。

From 加算演算子

3
Damith

これがあなたのコードがコンパイルされるものです

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文字列を処理します。

1
Aliostad