これは有効なC#コードです
var bob = "abc" + null + null + null + "123"; // abc123
これは有効なC#コードではありません
var wtf = null.ToString(); // compiler error
最初のステートメントが有効なのはなぜですか?
最初の1つが動作する理由:
[〜#〜] msdn [〜#〜] から:
文字列の連結操作では、C#コンパイラは空の文字列と同じように空の文字列を処理しますが、元の空の文字列の値を変換しません。
+二項演算子 の詳細:
二項演算子+は、一方または両方のオペランドが文字列型の場合に文字列の連結を実行します。
文字列連結のオペランドがnullの場合、空の文字列が置換されます。それ以外の場合、型オブジェクトから継承された仮想
ToString
メソッドを呼び出すことにより、非文字列引数は文字列表現に変換されます。
ToString
がnull
を返す場合、空の文字列が置換されます。
秒のエラーの理由は次のとおりです:
null(C#リファレンス) -nullキーワードは、null参照を表すリテラルであり、オブジェクトを参照しないものです。 nullは、参照型変数のデフォルト値です。
C#の_+
_演算子は、静的メソッドである_String.Concat
_に内部的に変換されるためです。そして、このメソッドはnull
を空の文字列のように扱います。 Reflectorで_String.Concat
_のソースを見ると、次のように表示されます。
_// while looping through the parameters
strArray[i] = (str == null) ? Empty : str;
// then concatenate that string array
_
(MSDNも言及しています: http://msdn.Microsoft.com/en-us/library/k9c94ey1.aspx )
一方、ToString()
はインスタンスメソッドであり、null
で呼び出すことはできません(null
に使用するタイプは?)。
最初のサンプルは次のように変換されます:
var bob = String.Concat("abc123", null, null, null, "abs123");
Concat
メソッドは入力をチェックし、nullを空の文字列として変換します
2番目のサンプルは次のように変換されます。
var wtf = ((object)null).ToString();
したがって、null
参照例外がここで生成されます
コードの最初の部分は_String.Concat
_のように扱われますが、
これは、文字列を追加するときにC#コンパイラが呼び出すものです。 "_abc" + null
_はString.Concat("abc", null)
に変換されます。
内部的には、このメソッドはnull
を_String.Empty
_に置き換えます。そのため、コードの最初の部分で例外がスローされないのはこのためです。それはちょうどのようなものです
_var bob = "abc" + string.Empty + string.Empty + string.Empty + "123"; //abc123
_
「null」はオブジェクトではないため、コードの2番目の部分で例外がスローされますnullキーワードは、null参照を表すリテラルですオブジェクトを参照しません。 nullは、参照型変数のデフォルト値です。
また、「ToString()
」は、オブジェクトのインスタンスから呼び出すことはできますが、リテラルから呼び出すことはできません。
.netより前のCOMフレームワークでは、文字列を受け取ったルーチンは、文字列を受け取ったときにそれを解放する必要がありました。空の文字列がルーチンに出入りすることは非常に一般的であり、nullポインターを「解放」しようとすることは正当な何もしない操作として定義されていたため、Microsoftはnull文字列ポインターが空の文字列を表すことを決定しました。
COMとの互換性を確保するため、.netの多くのルーチンは、nullオブジェクトを空の文字列としての正当な表現として解釈します。 .netとその言語のわずかな変更(インスタンスメンバーが「仮想として呼び出さない」を示すことを特に許可)をわずかに行うことで、Microsoftは宣言されたString型のnull
オブジェクトを空の文字列のように動作させることができました。マイクロソフトがそれを行っていた場合、Nullable<T>
を多少異なるように(Nullable<String>
--とにかくIMHOがやるべきことを許可するように)および/またはNullableString
タイプは、ほとんどString
と交換可能ですが、null
を有効な空の文字列とは見なしません。
そのままでは、null
が正当な空の文字列と見なされるコンテキストと、そうでないコンテキストがあります。非常に役立つ状況ではありませんが、プログラマーが知っておくべき状況です。一般に、stringValue
がnull
の場合、stringValue.someMember
という形式の式は失敗しますが、パラメーターとして文字列を受け入れるほとんどのフレームワークメソッドおよび演算子は、null
を空の文字列。
_'+'
_は中置演算子です。他の演算子と同様に、実際にはメソッドを呼び出しています。非中置バージョン"wow".Plus(null) == "wow"
を想像できます
実装者はこのようなことを決めました...
_class String
{
...
String Plus(ending)
{
if(ending == null) return this;
...
}
}
_
だから..あなたの例は
_var bob = "abc".Plus(null).Plus(null).Plus(null).Plus("123"); // abc123
_
と同じです
_var bob = "abc".Plus("123"); // abc123
_
Nullは文字列になりません。したがって、null.ToString()
はnull.VoteMyAnswer()
と違いはありません。 ;)
このディスカッションスレッドで、誰かが何もないところから文字列を作ることはできません。(これは私が思うに素敵なフレーズです)と言いました。ただし、次の例に示すように、yes-you can :-)
var x = null + (string)null;
var wtf = x.ToString();
正常に動作し、例外をまったくスローしません。唯一の違いは、nullの1つを文字列にキャストする必要があることです。(string)キャストを削除すると、サンプルはコンパイルされますが、実行時例外がスローされます: "Operator ' + 'は、タイプ' <null> 'および' <null> '"のオペランドではあいまいです。
N.B。上記のコード例では、xの値は予想どおりnullではなく、オペランドの1つを文字列にキャストした後の実際の空の文字列です。
別の興味深い事実は、C#/ .NETではnull
の処理方法が常に同じとは限らない異なるデータ型を考慮する場合です。例えば:
int? x = 1; // string x = "1";
x = x + null + null;
Console.WriteLine((x==null) ? "<null>" : x.ToString());
コードスニペットの1行目について:x
が値int?
を含むNULL可能整数変数(つまり1
)の場合、結果<null>
戻ります。値が"1"
の文字列(コメントに示されている)の場合、"1"
ではなく<null>
が返されます。
N.B。また興味深い:最初の行にvar x = 1;
を使用している場合、実行時エラーが発生します。どうして?代入により、変数x
がデータ型int
に変換されるためです。コンパイラはここでint?
を想定していないため、null
が追加された2行目で失敗します。
これは、オブジェクトを参照しないliteralであるためだと思います。 ToString()
にはobject
が必要です。
null
を文字列に追加しても、単に無視されます。 null
(2番目の例)はオブジェクトのインスタンスではないため、ToString()
メソッドさえありません。それは単なる文字通りです。
文字列を連結するときにstring.Empty
とnull
の間に違いがないためです。 string.Format
にもnullを渡すことができます。しかし、null
でメソッドを呼び出そうとしていますが、これは常にNullReferenceException
になり、そのためコンパイラエラーが生成されます。
何らかの理由で本当にやりたい場合は、null
をチェックしてからstring.Empty
を返す拡張メソッドを書くことができます。しかし、そのような拡張機能は、絶対に必要な場合にのみ使用する必要があります(私の意見では)。
一般的には、仕様に応じてパラメータとしてnullを受け入れることは有効でも無効でもかまいませんが、nullでメソッドを呼び出すことは常に無効です。
それが、文字列の場合に+演算子のオペランドがnullになる理由です。これはちょっとVBこと(ごめんなさい)プログラマーの生活を楽にするか、プログラマーがnullを扱えないと仮定します。この仕様に完全に反対です。'unknown '+' anything 'is 'わからない'...