String.Emptyと“”の違いは何ですか(空の文字列)?

StackOverflow https://stackoverflow.com/questions/151472

  •  02-07-2019
  •  | 
  •  

質問

.NETでは、 String.Empty "" の違いは何ですか、それらは互換性がありますか? String.Empty が保証する平等は問題ではありませんか?

役に立ちましたか?

解決

バージョン2.0より前の.NETでは、"" はオブジェクトを作成し、 string.Empty はオブジェクトを作成しません ref 。これにより、 string.Empty がより多くなります。効率的。

.NETバージョン2.0以降では、すべての&quot;&quot; は同じ文字列リテラルを参照します。つまり、&quot;&quot; は< code> .Empty ですが、 .Length == 0 ほど高速ではありません。

.Length == 0 は最速のオプションですが、 .Empty はわずかにクリーンなコードになります。

詳細については、 .NET仕様をご覧ください

他のヒント

  

String.Emptyと&quot;&quot;の違いは何ですか?   交換可能

string.Empty は読み取り専用フィールドで、&quot;&quot; はコンパイル時定数です。動作が異なる場所は次のとおりです。

C#4.0以降のデフォルトのパラメーター値

void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
    //... implementation
}

switchステートメントのケース式

string str = "";
switch(str)
{
    case string.Empty: // Error: A constant value is expected. 
        break;

    case "":
        break;

}

属性引数

[Example(String.Empty)]
// Error: An attribute argument must be a constant expression, typeof expression 
//        or array creation expression of an attribute parameter type

以前の回答は.NET 1.1で正しかった(リンクした投稿の日付を見てください:2003)。 .NET 2.0以降では、本質的に違いはありません。 JITは、いずれにしてもヒープ上の同じオブジェクトを参照することになります。

C#仕様のセクション2.4.4.5によると: http://msdn.microsoft.com/en-us/ library / aa691090(VS.71).aspx

  

各文字列リテラルは、必ずしも新しい文字列インスタンスになるとは限りません。文字列の等価演算子(7.9.7項)に基づいて等価な2つ以上の文字列リテラルが同じアセンブリにある場合、これらの文字列リテラルは同じ文字列インスタンスを参照します。

誰かがブラッド・エイブラムの投稿のコメントでこれについて言及している

要約すると、&quot;&quot;の実際の結果vs. String.Emptyはnilです。 JITは最終的にそれを把握します。

個人的には、JITが私よりもずっと賢いことを発見したので、そのようなマイクロコンパイラの最適化であまり賢くならないようにしています。 JITはfor()ループを展開し、冗長コード、インラインメソッドなどをより適切に、IまたはC#コンパイラーが事前に予想するよりも適切なタイミングで展開します。 JITに任せる:)

String.Empty readonly フィールドで、&quot;&quot; const です。これは、定数ではないため、switchステートメントで String.Empty を使用できないことを意味します。

別の違いは、String.Emptyがより大きなCILコードを生成することです。一方、&quot;&quot;を参照するコードString.Emptyは同じ長さで、コンパイラは文字列の連結を最適化しません(Eric Lippertのブログ投稿)。以下の同等の関数

string foo()
{
    return "foo" + "";
}
string bar()
{
    return "bar" + string.Empty;
}

このILを生成

.method private hidebysig instance string foo() cil managed
{
    .maxstack 8
    L_0000: ldstr "foo"
    L_0005: ret 
}
.method private hidebysig instance string bar() cil managed
{
    .maxstack 8
    L_0000: ldstr "bar"
    L_0005: ldsfld string [mscorlib]System.String::Empty
    L_000a: call string [mscorlib]System.String::Concat(string, string)
    L_000f: ret 
}

上記の回答は技術的には正しいですが、コードの読みやすさと例外の発生を最小限に抑えるために、本当に使用したいのは String.IsNullOrEmpty(s)

単純であるが明らかでない理由のために、&quot;&quot; ではなく String.Empty を使用する傾向があります。 &quot;&#65279;&#65279;&#65279;&#65279;&#65279;&#65279;&#65279;&#65279;&#65279;&#65279;&#65279;& #65279;&#65279;&#65279;&#65279;&#65279;&#65279;&#65279;&#65279;&#65279;&quot; &quot;&quot; は同じではなく、最初のものには実際には16個のゼロ幅文字が含まれています。明らかに、有能な開発者がコードに幅文字を入れたり、コードに入れたりすることはありませんが、彼らがそこに入ると、メンテナンスの悪夢になる可能性があります。

注:

&quot;&quot; ではなく、 String.Empty を使用します。

  

これはメモリの使用よりも速度の方が重要ですが、役に立つヒントです。の   &quot;&quot; はリテラルなので、リテラルとして機能します。最初の使用時には   作成され、以下の用途ではその参照が返されます。唯一   &quot;&quot; のインスタンスは、何回もメモリに保存されます   これを使って!ここにはメモリのペナルティはありません。 問題は   &quot;&quot; が使用されるたびに、比較ループが実行され、   &quot;&quot; は既にインターンプールにあります。 反対側では、 String.Empty    .NET Frameworkメモリゾーンに保存されている&quot;&quot; への参照です。    String.Empty はVB.NETとC#の同じメモリアドレスを指している   アプリケーション。なぜ&quot;&quot; が必要になるたびに参照を検索するのか    String.Empty にその参照がある場合?

参照: String.Empty vs &quot;&quot;

String.Emptyはオブジェクトを作成しませんが、&quot;&quot;します。 こちらで指摘されている違いは些細なことですが、ただし。

&quot;&quot;のすべてのインスタンス同じ、インターン化された文字列リテラルです(または、そうする必要があります)。したがって、&quot;&quot;を使用するたびにヒープに新しいオブジェクトをスローすることはありません。ただし、同じインターンオブジェクトへの参照を作成するだけです。そうは言っても、string.Emptyを好みます。コードが読みやすくなると思います。

string mystring = "";
ldstr ""

ldstr は、メタデータに保存されている文字列リテラルに新しいオブジェクト参照をプッシュします。

string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty

ldsfld は、静的フィールドの値を評価スタックにプッシュします

私は&quot;&quot; の代わりに String.Empty を使用する傾向があります。

Entity Frameworkの観点からこれについて説明します。EFバージョン6.1.3は、String.Emptyおよび&quot;&quot;を処理するようです。検証時とは異なります。

string.Emptyは、検証のためにnull値として扱われ、必須(属性)フィールドで使用された場合、検証エラーをスローします。ここで&quot;&quot;検証に合格し、エラーをスローしません。

この問題は、EF 7+で解決される可能性があります。参照: - https://github.com/aspnet/EntityFramework/issues/2610 )。

編集:[Required(AllowEmptyStrings = true)]はこの問題を解決し、string.Emptyの検証を許可します。

String.Emptyはコンパイル時定数ではないため、関数定義のデフォルト値として使用することはできません。

public void test(int i=0,string s="")
    {
      // Function Body
    }
  

Eric Lippert wrote (2013年6月17日):
&quot; C#コンパイラで作業した最初のアルゴリズムは、文字列の連結を処理するオプティマイザーでした。 残念ながら、これらの最適化をRoslynコードベースに移植することができませんでした。誰かがそれに到達することを願っています!&quot;

2019年1月時点での Roslyn x64 の結果は次のとおりです。このページの他の回答については意見が一致しているにもかかわらず、現在のx64 JITがこれらすべてのケースを処理しているようには見えません同様に、すべてを言って完了したとき。

ただし、これらの例の1つだけが実際に String.Concat を呼び出すことになります。これは、(最適化の監視とは対照的に)あいまいな正確さの理由によるものと推測しています。他の違いを説明するのは難しいようです。


default(String)&nbsp; +&nbsp; {default(String)、&nbsp; &quot;&quot;、&nbsp; String.Empty}

static String s00() => default(String) + default(String);
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s01() => default(String) + "";
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s02() => default(String) + String.Empty;
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

&quot;&quot; &nbsp; +&nbsp; {default(String)、&nbsp; &quot;&quot;、&nbsp; String.Empty}

static String s03() => "" + default(String);
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s04() => "" + "";
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s05() => "" + String.Empty;
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

String.Empty&nbsp; +&nbsp; {default(String)、&nbsp; &quot;&quot;、&nbsp; String.Empty}

static String s06() => String.Empty + default(String);
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

static String s07() => String.Empty + "";
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

static String s08() => String.Empty + String.Empty;
    mov  rcx,[String::Empty]
    mov  rcx,qword ptr [rcx]
    mov  qword ptr [rsp+20h],rcx
    mov  rcx,qword ptr [rsp+20h]
    mov  rdx,qword ptr [rsp+20h]
    call F330CF60                 ; <-- String.Concat
    nop
    add  rsp,28h
    ret


テストの詳細

Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
AMD64 Release
[MethodImpl(MethodImplOptions.NoInlining)]
'SuppressJitOptimization' = false

コードを視覚的にスキャンしている場合、&quot;&quot;文字列が色付けされるように色付けされて表示されます。 string.Emptyは、通常のクラスメンバーアクセスのように見えます。クイックルックでは、「&quot;&quot;または意味を直観します。

文字列を見つけます(スタックオーバーフローの色付けは正確には役立ちませんが、VSではこれはより明白です):

var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;

ここの誰もがいくつかの良い理論的説明をしました。同様の疑いがありました。そこで、基本的なコーディングを試しました。そして、違いを見つけました。違いがあります。

string str=null;
Console.WriteLine(str.Length);  // Exception(NullRefernceException) for pointing to null reference. 


string str = string.Empty;
Console.WriteLine(str.Length);  // 0

したがって、「Null」と思われます。は絶対に無効であることを意味します。 &quot; String.Empty&quot;何らかの値が含まれていますが、空であることを意味します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top