web-dev-qa-db-ja.com

ヌル文字列を連結するのに「null.ToString()」を呼び出さないのはなぜ有効なのですか?

これは有効なC#コードです

var bob = "abc" + null + null + null + "123";  // abc123

これは有効なC#コードではありません

var wtf = null.ToString(); // compiler error

最初のステートメントが有効なのはなぜですか?

121
superlogical

最初の1つが動作する理由:

[〜#〜] msdn [〜#〜] から:

文字列の連結操作では、C#コンパイラは空の文字列と同じように空の文字列を処理しますが、元の空の文字列の値を変換しません。

+二項演算子 の詳細:

二項演算子+は、一方または両方のオペランドが文字列型の場合に文字列の連結を実行します。

文字列連結のオペランドがnullの場合、空の文字列が置換されます。それ以外の場合、型オブジェクトから継承された仮想ToStringメソッドを呼び出すことにより、非文字列引数は文字列表現に変換されます。

ToStringnullを返す場合、空の文字列が置換されます。

秒のエラーの理由は次のとおりです:

null(C#リファレンス) -nullキーワードは、null参照を表すリテラルであり、オブジェクトを参照しないものです。 nullは、参照型変数のデフォルト値です。

159
Pranay Rana

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に使用するタイプは?)。

107
Botz3000

最初のサンプルは次のように変換されます:

var bob = String.Concat("abc123", null, null, null, "abs123");

Concatメソッドは入力をチェックし、nullを空の文字列として変換します

2番目のサンプルは次のように変換されます。

var wtf = ((object)null).ToString();

したがって、null参照例外がここで生成されます

29

コードの最初の部分は_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()」は、オブジェクトのインスタンスから呼び出すことはできますが、リテラルから呼び出すことはできません。

11
Talha

.netより前のCOMフレームワークでは、文字列を受け取ったルーチンは、文字列を受け取ったときにそれを解放する必要がありました。空の文字列がルーチンに出入りすることは非常に一般的であり、nullポインターを「解放」しようとすることは正当な何もしない操作として定義されていたため、Microsoftはnull文字列ポインターが空の文字列を表すことを決定しました。

COMとの互換性を確保するため、.netの多くのルーチンは、nullオブジェクトを空の文字列としての正当な表現として解釈します。 .netとその言語のわずかな変更(インスタンスメンバーが「仮想として呼び出さない」を示すことを特に許可)をわずかに行うことで、Microsoftは宣言されたString型のnullオブジェクトを空の文字列のように動作させることができました。マイクロソフトがそれを行っていた場合、Nullable<T>を多少異なるように(Nullable<String>--とにかくIMHOがやるべきことを許可するように)および/またはNullableStringタイプは、ほとんどStringと交換可能ですが、nullを有効な空の文字列とは見なしません。

そのままでは、nullが正当な空の文字列と見なされるコンテキストと、そうでないコンテキストがあります。非常に役立つ状況ではありませんが、プログラマーが知っておくべき状況です。一般に、stringValuenullの場合、stringValue.someMemberという形式の式は失敗しますが、パラメーターとして文字列を受け入れるほとんどのフレームワークメソッドおよび演算子は、nullを空の文字列。

9
supercat

_'+'_は中置演算子です。他の演算子と同様に、実際にはメソッドを呼び出しています。非中置バージョン"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()と違いはありません。 ;)

5
Nigel Thorne

このディスカッションスレッドで、誰かが何もないところから文字列を作ることはできません。(これは私が思うに素敵なフレーズです)と言いました。ただし、次の例に示すように、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行目で失敗します。

3
Matt

これは、オブジェクトを参照しないliteralであるためだと思います。 ToString()にはobjectが必要です。

3
Saeed Neamati

nullを文字列に追加しても、単に無視されます。 null(2番目の例)はオブジェクトのインスタンスではないため、ToString()メソッドさえありません。それは単なる文字通りです。

2

文字列を連結するときにstring.Emptynullの間に違いがないためです。 string.Formatにもnullを渡すことができます。しかし、nullでメソッドを呼び出そうとしていますが、これは常にNullReferenceExceptionになり、そのためコンパイラエラーが生成されます。
何らかの理由で本当にやりたい場合は、nullをチェックしてからstring.Emptyを返す拡張メソッドを書くことができます。しかし、そのような拡張機能は、絶対に必要な場合にのみ使用する必要があります(私の意見では)。

1
Franky

一般的には、仕様に応じてパラメータとしてnullを受け入れることは有効でも無効でもかまいませんが、nullでメソッドを呼び出すことは常に無効です。


それが、文字列の場合に+演算子のオペランドがnullになる理由です。これはちょっとVBこと(ごめんなさい)プログラマーの生活を楽にするか、プログラマーがnullを扱えないと仮定します。この仕様に完全に反対です。'unknown '+' anything 'is 'わからない'...

0
g.pickardou