有効な C# コードは次のとおりです。
var samsung= "xyz" + null + null + null + null + "890"; // xyz890
これは無効な C# コードです。
var iphone= null.ToString(); // compiler error
最初のステートメントが有効で、2 番目のステートメントが無効である理由と方法は?
有効な C# コードは次のとおりです。
var samsung= "xyz" + null + null + null + null + "890"; // xyz890
これは無効な C# コードです。
var iphone= null.ToString(); // compiler error
最初のステートメントが有効で、2 番目のステートメントが無効である理由と方法は?
+
演算子は文字列を連結するためにnull
使用され、文字列クラスのインスタンスであるため、演算子の引数として使用できます。"xyz" + null
最終的に文字列「xyz」が返されるため、実際にを追加するまでこのプロセスが繰り返されます"890"
。
nullはメソッドへの引数の文字列オブジェクトとして使用できますが、メソッド呼び出しを処理するものがないため、実際にメソッドを呼び出すことはできません。
メソッドは、オブジェクトが外部リクエストを処理する方法と考えてください。物事はもう少し意味があります。何を処理するかを引数としてオブジェクトにリクエストを送信することはできますnull
が、実際にnull
何かを処理するように要求することはできません。
+
演算子は、次のようなグローバル静的関数と考えることができます。
+(string leftHandSide, string rightHandSide) {
if (leftHandSide == null)
leftHandSide = string.Empty;
if (rightHandSide == null)
rightHandSide = string.Empty;
string returnValue;
// concatenate string
return returnValue;
}
この文字列連結メソッドは静的であるため、呼び出すインスタンスを必要とせず、null値を処理します。ただし、呼び出しようとするとToString
、null
オブジェクトのインスタンスがないToString
ため、呼び出す方法がないため、例外が発生します。
C# コンパイラは、連結内の null を空の文字列と見なします。
var samsung= "xyz" + null + null + null + null + "890";
等しい
var samsung= "xyz" + ""+ ""+ ""+ ""+ "890";
呼び出そnull.toString()
うとすると、本質的に null オブジェクトでメソッドを呼び出そうとしています。これは (コンパイルされた場合) 常にNullReferenceException
.
最初の行では、文字列を連結しています。 null
は何もないので、本質的にあなたは得てxyz890
います。それはやっているようなものです1+0+0+0+4
が、あなたの秒で、あなたは. 何もないので、呼び出すものは何もありません。初期化されていない変数でメソッドを呼び出そうとしています。ToString()
null
null
ToString()
は参照型であるためstring
、 null は暗黙的に に変換できますstring
。そして、最初のケースでは、一連の+
演算子は次のように変換されますString.Concat(obj1, obj2, obj3, ...)
コードをコンパイルするには、次のように呼び出しますConvert.ToString
。
var iphone = Convert.ToString(null);
これは仕様によるものです。C# 言語仕様を読むことができます。見積もり:
文字列連結:
string operator +(string x, string y); string operator +(string x, object y); string operator +(object x, string y);
+
二項演算子のこれらのオーバーロードは、文字列連結を実行します。文字列連結のオペランドが の場合null
、空文字列が代入されます。それ以外の場合、文字列以外の引数はToString
、 type から継承された仮想メソッドを呼び出すことによって文字列表現に変換されobject
ます。ToString
を返す場合null
、空の文字列が代用されます。[...]
したがって、他の人が言っ+
たように、2 つの引数を取り、そのうちの 1 つまたは両方が であっても OK である一種のメソッドと考えてnull
ください。
どのような場合でも参照に対してメソッドを呼び出すことはできない 最初のケースでは、コンパイラは文字列定数をプリコンパイルしてnull
ため、コンパイラはそれを許可しません。"xyz890"
、正当な代入を行います。
一般に、引数をサポートするコンパイルの+
演算子。string
String.Concat(s1, s2, ...)
null
2 番目のケースをより正確に言うと、実際の問題はそれが null ポインターであることではなく、メソッドをバインドする型がないことです。他のコメントで指摘されているように、null
任意の参照型にキャストでき、問題なくコンパイルできます。
((string)null).ToString(); // compiles, but fails at run-time.
+ 演算子は、次のような静的関数に変換されます。
public static string Concat(string first, string second) {...}
関数にパラメーターとして null を渡すことは問題ではありません。それはうまく通過します。その関数は、パラメーターを連結する前に、どちらのパラメーターも null でないことをたまたまチェックします。パラメータのいずれかが null の場合、例外が発生しないように空の文字列として扱われます。ここで重要な点は、この関数によって最初に null チェックされるまで、文字列のインスタンス メンバーが呼び出されないことです。
コンパイル時に評価されるものに対してインスタンス関数をnull.ToString()
呼び出すと、例外が発生します。null
これはまさにそのケースの定義です。
IL を見ると、コンパイラが十分にスマートで、null 値を削除して連結文字列を作成するだけであることがわかります。前述のように、null.ToString(); を実行することはできません。string.Empty を実行するか、文字列を null に割り当てることができます。
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 8 (0x8)
.maxstack 1
.locals init ([0] string samsung)
IL_0000: nop
IL_0001: ldstr "xyz890" //null has been removed by compiler.
IL_0006: stloc.0
IL_0007: ret
} // end of method Program::Main
編集
ニールソンのコメントを展開します。null は nil 参照を表すため、文字列 concat の処理方法は、操作などの C# で許可されていると言っても過言ではありません。null値を省略するバイト配列構築を使用しているため、nullを連結しているように見えるだけだと思います。