String.Emptyと“”の違いは何ですか(空の文字列)?
-
02-07-2019 - |
質問
.NETでは、 String.Empty
と""
の違いは何ですか、それらは互換性がありますか? String.Empty
が保証する平等は問題ではありませんか?
解決
バージョン2.0より前の.NETでは、""
はオブジェクトを作成し、 string.Empty
はオブジェクトを作成しません ref 。これにより、 string.Empty
がより多くなります。効率的。
.NETバージョン2.0以降では、すべての""
は同じ文字列リテラルを参照します。つまり、""
は< 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個のゼロ幅文字が含まれています。明らかに、有能な開発者がコードに幅文字を入れたり、コードに入れたりすることはありませんが、彼らがそこに入ると、メンテナンスの悪夢になる可能性があります。
注:
-
U + FEFF を使用しました例。
-
SOがこれらの文字を食べるかどうかはわかりませんが、多くのゼロ幅文字の1つを試してみてください
- に感謝しただけです。 li>
&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はオブジェクトを作成しませんが、&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;何らかの値が含まれていますが、空であることを意味します。