问题
In .NET, what is the difference between String.Empty
and \"\"
, and are they interchangable, or is there some underlying reference or Localization issues around equality that String.Empty
will ensure are not a problem?
回答1:
In .NET prior to version 2.0, ""
creates an object while string.Empty
creates no objectref, which makes string.Empty
more efficient.
In version 2.0 and later of .NET, all occurrences of ""
refer to the same string literal, which means ""
is equivalent to .Empty
, but still not as fast as .Length == 0
.
.Length == 0
is the fastest option, but .Empty
makes for slightly cleaner code.
See the .NET specification for more information.
回答2:
what is the difference between String.Empty and "", and are they interchangable
string.Empty is a read-only field whereas ""
is a compile time constant. Places where they behave differently are:
Default Parameter value in C# 4.0 or higher
void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
//... implementation
}
Case expression in switch statement
string str = "";
switch(str)
{
case string.Empty: // Error: A constant value is expected.
break;
case "":
break;
}
Attribute arguments
[Example(String.Empty)]
// Error: An attribute argument must be a constant expression, typeof expression
// or array creation expression of an attribute parameter type
回答3:
The previous answers were correct for .NET 1.1 (look at the date of the post they linked: 2003). As of .NET 2.0 and later, there is essentially no difference. The JIT will end up referencing the same object on the heap anyhow.
According to the C# specification, section 2.4.4.5: http://msdn.microsoft.com/en-us/library/aa691090(VS.71).aspx
Each string literal does not necessarily result in a new string instance. When two or more string literals that are equivalent according to the string equality operator (Section 7.9.7) appear in the same assembly, these string literals refer to the same string instance.
Someone even mentions this in the comments of Brad Abram's post
In summary, the practical result of "" vs. String.Empty is nil. The JIT will figure it out in the end.
I have found, personally, that the JIT is way smarter than me and so I try not to get too clever with micro-compiler optimizations like that. The JIT will unfold for() loops, remove redundant code, inline methods, etc better and at more appropriate times than either I or the C# compiler could ever anticipate before hand. Let the JIT do its job :)
回答4:
String.Empty
is a readonly field while ""
is a const. This means you can't use String.Empty
in a switch statement because it is not a constant.
回答5:
Another difference is that String.Empty generates larger CIL code. While the code for referencing "" and String.Empty is the same length, the compiler doesn't optimize string concatenation (see Eric Lippert's blog post) for String.Empty arguments. The following equivalent functions
string foo()
{
return "foo" + "";
}
string bar()
{
return "bar" + string.Empty;
}
generate this 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
}
回答6:
The above answers are technically correct, but what you may really want to use, for best code readability and least chance of an exception is String.IsNullOrEmpty(s)
回答7:
I tend to use String.Empty
rather than ""
for one simple, yet not obvious reason:
""
and ""
are NOT the same, the first one actually has 16 zero width characters in it. Obviously no competent developer is going to put and zero width characters into their code, but if they do get in there, it can be a maintenance nightmare.
Notes:
I used U+FEFF in this example.
Not sure if SO is going to eat those characters, but try it yourself with one of the many zero-width characters
I only came upon this thanks to https://codegolf.stackexchange.com/
回答8:
String.Empty does not create an object whereas "" does. The difference, as pointed out here, is trivial, however.
回答9:
It just doesn't matter!
Some past discussion of this:
http://www.codinghorror.com/blog/archives/000185.html
http://blogs.msdn.com/brada/archive/2003/04/22/49997.aspx
http://blogs.msdn.com/brada/archive/2003/04/27/50014.aspx
回答10:
All instances of "" are the same, interned string literal (or they should be). So you really won't be throwing a new object on the heap every time you use "" but just creating a reference to the same, interned object. Having said that, I prefer string.Empty. I think it makes code more readable.
回答11:
Use String.Empty
rather than ""
.
This is more for speed than memory usage but it is a useful tip. The
""
is a literal so will act as a literal: on the first use it is created and for the following uses its reference is returned. Only one instance of""
will be stored in memory no matter how many times we use it! I don't see any memory penalties here. The problem is that each time the""
is used, a comparing loop is executed to check if the""
is already in the intern pool. On the other side,String.Empty
is a reference to a""
stored in the .NET Framework memory zone.String.Empty
is pointing to same memory address for VB.NET and C# applications. So why search for a reference each time you need""
when you have that reference inString.Empty
?
Reference: String.Empty vs ""
回答12:
string mystring = "";
ldstr ""
ldstr
pushes a new object reference to a string literal stored in the metadata.
string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty
ldsfld
pushes the value of a static field onto the evaluation stack
I tend to use String.Empty
instead of ""
because IMHO it's clearer and less VB-ish.
回答13:
Eric Lippert wrote (June 17, 2013):
"The first algorithm I ever worked on in the C# compiler was the optimizer that handles string concatenations. Unfortunately I did not manage to port these optimizations to the Roslyn codebase before I left; hopefully someone will get to that!"
Here are some Roslyn x64 results as of January 2019. Despite the consensus remarks of the other answers on this page, it does not appear to me that the current x64 JIT is treating all of these cases identically, when all is said and done.
Note in particular, however, that only one of these examples actually ends up calling String.Concat
, and I'm guessing that that's for obscure correctness reasons (as opposed to an optimization oversight). The other differences seem harder to explain.
default(String) + { default(String), "", 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
"" + { default(String), "", 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 + { default(String), "", 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
Test details
Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
AMD64 Release
[MethodImpl(MethodImplOptions.NoInlining)]
'SuppressJitOptimization' = false
回答14:
Coming at this from an Entity Framework point of view: EF versions 6.1.3 appears to treat String.Empty and "" differently when validating.
string.Empty is treated as a null value for validation purposes and will throw a validation error if it's used on a Required (attributed) field; where as "" will pass validation and not throw the error.
This problem may be resolved in EF 7+. Reference: - https://github.com/aspnet/EntityFramework/issues/2610 ).
Edit: [Required(AllowEmptyStrings = true)] will resolve this issue, allowing string.Empty to validate.
回答15:
Since String.Empty is not a compile-time constant you cannot use it as a default value in function definition.
public void test(int i=0,string s="")
{
// Function Body
}
回答16:
When you're visually scanning through code, "" appears colorized the way strings are colorized. string.Empty looks like a regular class-member-access. During a quick look, its easier to spot "" or intuit the meaning.
Spot the strings (stack overflow colorization isn't exactly helping, but in VS this is more obvious):
var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;
回答17:
Everybody here gave some good theoretical clarification. I had a similar doubt. So I tried a basic coding on it. And I found a difference. Here's the difference.
string str=null;
Console.WriteLine(str.Length); // Exception(NullRefernceException) for pointing to null reference.
string str = string.Empty;
Console.WriteLine(str.Length); // 0
So it seems "Null" means absolutely void & "String.Empty" means It contains some kind of value, but it is empty.
来源:https://stackoverflow.com/questions/151472/what-is-the-difference-between-string-empty-and-empty-string