これは有効なC#コードです
var bob = "abc" + null + null + null + "123"; // abc123
これは有効なC#コードではありません
var wtf = null.ToString(); // compiler error
最初のステートメントが有効なのはなぜですか?
class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
これは有効なC#コードです
var bob = "abc" + null + null + null + "123"; // abc123
これは有効なC#コードではありません
var wtf = null.ToString(); // compiler error
最初のステートメントが有効なのはなぜですか?
class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
回答:
最初のものが機能する理由:
MSDNから:
文字列連結演算では、C#コンパイラはnull文字列を空の文字列と同様に扱いますが、元のnull文字列の値は変換しません。
詳細情報+バイナリ演算子:
二項+演算子は、一方または両方のオペランドが文字列型である場合、文字列連結を実行します。
文字列連結のオペランドがnullの場合、空の文字列が置換されます。それ以外の場合、文字列以外の引数は
ToString、型オブジェクトから継承された仮想メソッドを呼び出すことにより、文字列表現に変換されます。がを
ToString返すnull場合、空の文字列が置換されます。
秒単位のエラーの理由は次のとおりです。
null(C#参照) -nullキーワードは、オブジェクトを参照しないnull参照を表すリテラルです。nullは、参照型変数のデフォルト値です。
wtf = ((String)null).ToString();私が最近Javaで作業していて、nullのキャストが可能な場合、C#で作業してからしばらく経ちました。
null.ToString()vsと考えてくださいToString(null)。
+C#の演算子は内部的にに変換されるためString.Concat、これは静的メソッドです。そして、このメソッドはたまたまnull空の文字列のように扱われます。String.ConcatReflector のソースを見ると、次のことがわかります。
// 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ますか?)。
+、C#の文字列の演算子はの構文糖衣ですString.Concat。
__arglist、およびparamsオブジェクト配列バージョンです。
Concat常にnull以外の文字列の配列を与えられた、または他の何かが起こっても、非ヌル文字列の新しい配列を作成しますか?
最初のサンプルはに翻訳されます。
var bob = String.Concat("abc123", null, null, null, "abs123");
このConcatメソッドは入力をチェックし、nullを空の文字列として変換します
第二のサンプルをに翻訳されます。
var wtf = ((object)null).ToString();
したがって、null参照例外がここで生成されます
AccessViolationExceptionがスローされます:)
((object)null).ToString()=> AccessViolation ((object)1 as string).ToString()=>NullReference
((object)null).ToString()中に入れたとき、try/catch私も得るNullReferenceException。
あなたのコードの最初の部分は、ちょうどそれのように扱われ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()」は、オブジェクトのインスタンスから呼び出すことはできますが、リテラルからは呼び出せないメソッドです。
String.Emptyと等しくないnull。のようないくつかのメソッドでは同じように扱われString.Concatます。たとえば、文字列変数をに設定している場合null、C#はString.Empty、そのメソッドを呼び出そうとしても、置換されません。
nullはString.EmptyC#のようには扱われませんが、C#の場合と同様に扱われString.Concatます。これは、文字列を追加するときにC#コンパイラが呼び出すものです。"abc" + nullに翻訳されString.Concat("abc", null)、内部的にそのメソッドはに置き換えnullられString.Emptyます。2番目の部分は完全に正しいです。
.netに先行するCOMフレームワークでは、文字列を受け取ったルーチンは、それを使用してそれを解放する必要がありました。空の文字列がルーチンとの間でやり取りされることは非常に一般的であり、ヌルポインターを「解放」する試みは正当な何もしない操作として定義されていたため、Microsoftは空の文字列を表すヌル文字列ポインターを持つことを決定しました。
COMとの互換性を確保するために、.netの多くのルーチンはnullオブジェクトを正当な表現として空の文字列として解釈します。いくつかのわずかな変更.netとその言語(特にインスタンスメンバーが「仮想として呼び出さない」を示すことを可能にする)により、Microsoft nullは宣言型Stringのオブジェクトを空の文字列のように動作させることができました。マイクロソフトがそれを行っていた場合、Nullable<T>(Nullable<String>とにかくIMHOがやるべきことを許可するために)多少異なる方法で作業を行うか、またはNullableStringとほとんど互換性Stringがあるが、null有効な空の文字列として。
そのままでは、nullaが正当な空の文字列と見なされるコンテキストとそうでないコンテキストがあります。ひどく役立つ状況ではありませんが、プログラマーが知っておくべき状況です。一般に、フォームの式はis stringValue.someMemberif stringValueで失敗nullしますが、パラメータとして文字列を受け入れるほとんどのフレームワークメソッドおよび演算子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()。;)
var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");ます。演算子のオーバーロードは、彼らの心の静的メソッドです:msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspxは彼らがいなかった、var bob = null + "abc";または特にstring bob = null + null;有効ではありません。
誰かがこのディスカッションスレッドで、何もないところから文字列を作成することはできないと述べました。 (私が思うに、これは素晴らしいフレーズです)。しかし、はい-次の例に示すように、:-) できます。
var x = null + (string)null;
var wtf = x.ToString();
正常に動作し、例外をまったくスローしません。唯一の違いは、nullの1つを文字列にキャストする必要があることです。(文字列)キャストを削除した場合、例は引き続きコンパイルされますが、実行時例外がスローされます。 「<null>」と「<null>」を入力します。
注意上記のコード例では、xの値は期待どおりにnullではなく、オペランドの1つを文字列にキャストした後は実際には空の文字列です。
もう1つの興味深い事実は、C#/ .NETでは、null異なるデータ型を考慮すると、処理方法が常に同じになるとは限らないことです。例えば:
int? x = 1; // string x = "1";
x = x + null + null;
Console.WriteLine((x==null) ? "<null>" : x.ToString());
コードスニペットの1行目について:がvalueを含むxnull許容整数変数(つまりint?)の場合1、結果が<null>返されます。それが値を持つ文字列(コメントに示されている)の場合"1"は、ではなく"1"戻ります<null>。
注:また興味深い:var x = 1;最初の行に使用している場合は、ランタイムエラーが発生します。どうして?これは、代入によって変数xがdatatypeに変わるためですint。これはnullにできません。コンパイラはint?ここを想定していないため、nullが追加されている2行目で失敗します。
null文字列への追加は単に無視されます。null(2番目の例では)はオブジェクトのインスタンスではないため、ToString()メソッドもありません。それは単なるリテラルです。
一般的に:仕様に応じてnullをパラメーターとして受け入れることは有効な場合と無効な場合がありますが、nullでメソッドを呼び出すことは常に無効です。
これが、文字列の場合に+演算子のオペランドがnullになる理由です。これは、プログラマーの生活を楽にするVBのこと(ごめんなさい)、またはプログラマーがnullを処理できない場合を想定しています。この仕様には完全に同意しません。'unknown' + 'anything'はまだ 'unknown'でなければなりません...
null.ToString()に名前が付けられているのは独特ですwtf。なぜ驚いたのですか?そもそもそれを呼び出すものがない場合、インスタンスメソッドを呼び出すことはできません。