string.Emptyプロパティのポイントは何ですか


35

プロパティstring foo = string.EmptyがBCLに含まれていたのはなぜですか?空の文字列(string foo = "")を使用するよりも冗長で明確ではないようです


6
Nitpick:それは言語の一部ではありません。これはBCLの一部です。VB.NETおよびF#は、他のすべての.NET言語と同様にそれを使用できます。
Oded

19
そうでなければ、次のような邪悪なことはできませんでしたtypeof(string).GetField("Empty").SetValue(null, " ");;)
メイソンウィーラー

1
@MasonWheeler-反射の喜び。本当の悪については、内省が必要ですよね?
オデッド

1
@ MasonWheeler、+ 1。ああ、ゴーグル、彼らは何もしません!]
マシャド

1
@MasonWheelerそれは純粋で蒸留された悪です。これ大好き。あなたが興味を持っているかどうか質問してください:それを書いた方が安全(そしてまともなパフォーマンス)ではないpublic static string Empty { get { return string.Intern(""); } }でしょうか?
ジェシーC.スライサー

回答:


55

私はここでしか仮定できません:

string.Empty明示性のために定義されています-文字列を初期化するとき、""(テスト中にプレースホルダーの代わりに、nullまたは言う" "だけで)実際に初期化子として明示的に意図されたコンテキストから明確でない場合があります。使用string.Emptyは、この種の難問に対する明確な答えです。

Cへの先祖返りでもあります。Cの空の文字列は空の文字列ではありません。これは、最初の文字がnull(したがって空)である文字配列であり、C#とは異なります。ここでの私のポイントは、異なる言語では、異なる方法で空の文字列を表すということです(そして、それらは異なる意味を持つかもしれません)- string.Emptyそのような曖昧さを排除します。

複数のオブジェクトについて他の人が言うこととは対照的に、コンパイル時に文字列リテラルがインターンされるため、これは問題ではありません。これにはstring.Empty- の値が含まれます""。これらのいずれかがコードで繰り返されるたびに、オブジェクトはインターンプールから取得されます。これはアプリドメインごとに当てはまります


5
これまでのところ唯一の正解であるため、+ 1。
psr

一部の言語に、空の文字列リテラルさえない場合あります。どうやら、標準のパスカルはしませんでした。
dan04

2
「Cの空の文字列は空の文字列ではありません」—しかし、を書く""とが得られる{'\0'}ので、空の文字列リテラルとそれを定義する他の迂回方法の間に違いはありません。
12

14

私がこれらを学んだ情報源を100%確信しているわけではありませんが、それを使用するためのいくつかのポイントは次のとおりです。

  • .NETアセンブリの各文字列は一意であるため、

    string foo = "";
    string bar = "";

    文字列は不変であるため、出力アセンブリに2つの文字列が生成されます。両方の参照があるとstring.Empty、アセンブリのサイズが小さくなります。

  • 明示性。string.Empty意図に出くわすと、それが空の文字列であることになっていることは明らかです。しかしfoo = ""、プログラマーがテスト中に文字列の内容を削除し、それを追加し直すのを忘れた場合、それはそのようになっているはずですか?

1
2つの同じ文字列をメモリに保持するのは奇妙な動作のようです。それが実際に行われていることですか?
リグ

36
実際、逆のことが行われます-これは文字列インターン(より正確には、リテラルのインターン)と呼ばれます。私は確かにそれがJavaとPythonで行われていることを知っており、.NET言語でもそうだと確信しています。もちろん、それは単一の翻訳単位の範囲でのみ発生する可能性があるため、ダイナミックローダーがそのようなデータを統合しない限り、プログラムファイルごとに1つの空の文字列になる可能性があります。それほどひどくはありません。

9
@delnanは絶対に正しい。""/ string.Emptyは抑留され、1つのオブジェクトのみが作成されます。
-Oded

11
@Andy-すべての文字列リテラルは.NETにインターンされます。すべての文字列ではありません。プログラムで作成された文字列は、デフォルトではインターンされません。MSDNのString.Internを参照してください。
-Oded

3
@Oded et alia:実際、あなたの誰も正確に正しい人はいません。まず、リテラルはアセンブリ内にインターンされますが、必ずしもアセンブリ全体にインターンされるわけではありません。第二に、空の文字列がアセンブリ間でインターンされるかどうかは実装の詳細です。CLRの一部のバージョンはサポートしますが、一部のバージョンはサポートしません。他の回答の1つには、この事実に関する私の記事へのリンクがあります。詳細についてはそれを参照してください。
エリックリッパー

2

のオブジェクトは作成されませんstring.Empty。を使用""すると、ほとんどの場合、文字列インターンプールから取得されるオブジェクトが作成されます。

過去に、人々はテストを実行String.Emptyし、わずかに速く出てきましたが、それは微最適化です。

String.Emptyは次のとおりです。

//The Empty constant holds the empty string value.   
//We need to call the String constructor so that the compiler doesn't mark 
//this as a literal.   
//Marking this as a literal would mean that it doesn't show up as a field 
//which we can access from native.  
public static readonly String Empty = ""; 

2
あなたのポイントは...ですか?

1
ポイントはString.Emptyは基本的に「」の定数です。より深い意味については、String.csの著者を見つけてください。:)
ジョンレイナー

0

メモリ消費の最適化と文字列比較の最適化の問題です。アプリケーションで空の文字列を使用するたびに、0文字を含む文字列オブジェクトを割り当てています。文字列の比較に関しては、文字(文字列)ではなく参照(ポインタ)を比較することで実行できます。空の文字列でも高速です。

アプリケーションで同じ文字列を何度も使用している場合、文字列でString.Intern()を呼び出すことで同じ種類のメカニズムを使用できます。ただし、各文字列を1回だけ使用する場合は、使用するメモリが増えるだけです。

そのため、String.Emptyは、ほとんどの.Netアプリケーションで実行する価値のある特別な場合の最適化にすぎません。そのため、BCLに統合されました。

このテーマの詳細については、Eric Lippertのブログ投稿を読むことを強くお勧めします。

彼のブログ投稿で参照されているこのドキュメントもご覧ください。


4
リンクのみの回答では良い回答が得られません。エリックがブログを再編すると、この答えは役に立たなくなります。ここに投稿を要約してください。手元にすべての情報があります。
ChrisF

7
@ChrisF:ブログを再編成することはできません。それは壊滅的な変化であり、あなたは私がそれらについてどのように感じているか知っています。
エリックリッパー

1
@EricLippert-私はあなたがそうすることは決してないことを理解していますが、リンクのみの答えは良い答えではないので、人々がそれを実現するよう奨励する必要があります。
ChrisF

3
@EricLippert一時的なリンクだけではありません。ここでは読者への礼儀正しさも重要です。少なくとも読者がリンクをたどるかどうかについて意見を述べることができるように、回答には少なくとも十分な内容が直接含まれている必要があります。そして、その答えは、SEのオフラインコピーであっても理にかなっているはずです。
ジル 'SO-悪であるのをやめる
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.