5

According to this answer, "" and string.Empty are very slightly different, in that "" creates an object, whereas string.Empty does not. That answer has the most votes on that question.

However, this answer says that there is no difference. It's a more recent answer as well.

So this was in 2010. Is this really the case? Do string.Empty and "" differ at all, even slightly?

EDIT: This question is meant to be an update to the linked questions, as I found it confusing that no modern answer had been presented, despite some debate on the matter.

Community
  • 1
  • 1
muttley91
  • 12,278
  • 33
  • 106
  • 160
  • 2
    Yes, they do. `string.Empty` is a singleton static reference to `""`, when you create a `""` empty string you aren't referencing that static reference, so they are, slightly, different. – Ron Beyer Jun 02 '15 at 17:50
  • 3
    http://blogs.msdn.com/b/ericlippert/archive/2009/09/28/string-interning-and-string-empty.aspx – asawyer Jun 02 '15 at 17:51
  • 1
    For the average bear, the real difference is in the writing style. `String.Empty` is more explicit, its intentions are clear. `""` could mean "I just haven't decided what this string will contain yet. – MPelletier Jun 02 '15 at 17:52
  • possible duplicate of [What is the difference between String.Empty and "" (empty string)?](http://stackoverflow.com/questions/151472/what-is-the-difference-between-string-empty-and-empty-string) – rnofenko Jun 02 '15 at 17:54
  • I think the first answer compares from resources point of view while the second talks about functional aspect. Both are correct isolated to the specific context – Claudio Redi Jun 02 '15 at 17:55
  • What's your goal - are you just curious or are you trying to determine if you can _rely_ on them being the same reference? – D Stanley Jun 02 '15 at 18:00
  • 1
    Curiosity, mostly. I had a discussion with someone who insisted string.Empty was "better", but everything I've read suggests that there's really not much point to specifically using one or the other. Except for the debated notion that `""` creates a new string object every time. – muttley91 Jun 02 '15 at 18:08

3 Answers3

6

The language specification (C# 4.0) is actually silent on the subject.

According to CLR via C#, it depends entirely on the CLR and not on the C# compiler. A relevant quote from p. 341:

Even if an assembly has this attribute/flag [CompilationRelaxations.NoStringInterning] specified, the CLR may choose to intern the strings, but you should not count on this. In fact, you really should never write code that relies on strings being interned unless you have written code that explicitly calls the String’s Intern method yourself.

So using "" may or may not create an new string object. That depends on the CLR (version) being used. And there's also the possibility that the compiler folds constants, in which case "" would cost 1 object per assembly compilation unit, not per occurrence.

None of this has any relevant impact on memory use or speed, but the clear guideline should be that both ReferenceEquals(s1, "") and ReferenceEquals(s1, String.Empty) should be avoided.

And of course Object.Equals(s1, s2) and s1 == s2 always work fine on strings.

H H
  • 263,252
  • 30
  • 330
  • 514
  • Do you have any thought on which we should prefer? – Jodrell Jun 05 '15 at 08:36
  • No, not very deeps ones. The only criterion left is readability, I sometimes (initializations, arguments) prefer `String.Empty` but in string expressions I tend to use `""`. – H H Jun 05 '15 at 08:52
0

You can read right in String.Empty, the value of this field (String.Empty) is the zero-length string, "".

You can test that they refer to the same string with a small test.

void main()
{
    String first = "";
    String second = String.empty;

    bool test = Object.ReferenceEquals(first, second);
}

Test will return true which means they refer to the same object.

Another slight difference is that evaluating "" is slightly more optimal and efficient than String.empty.

EDIT:

static void Main ( string[] args )
{
    string s1 = "MyTest";
    string s2 = new   StringBuilder().Append("My").Append("Test").ToString();
    string s3 = String.Intern(s2);

    Console.WriteLine((Object)s2 == (Object)s1); // Different references.
    Console.WriteLine((Object)s3 == (Object)s1); // The same reference.
    Console.WriteLine();


    s1 = "";
    s2 = new StringBuilder().Append("").ToString();
    s3 = String.Empty;
    string s4 = String.Intern(s2);

    Console.WriteLine((Object)s2 == (Object)s1); // The same reference.
    Console.WriteLine((Object)s3 == (Object)s1); // The same reference.
    Console.WriteLine((Object)s4 == (Object)s1); // The same reference.
    Console.WriteLine((Object)s4 == (Object)s2); // The same reference.
}

It is quite obvious to tell with interning that a string literal is already interned. When stringbuilder creates a new String object, that has the same object, it isn't interned and the references to the object are not the same. However, when we String.Intern(s2) the method returns the same reference that is assigned to s1 and the reference is then assigned to s3.

Thought

Why then, do all the four cases return true. I know the string literal "" is interned, but why isn't using Stringbuilder to append "" to a new string object the same as "" even though technically it is a new object that is not interned.

Adam
  • 2,422
  • 18
  • 29
  • "the other answer" meaning the one by Evan or...? – Adam Jun 02 '15 at 17:58
  • 2
    `""` use interning too (otherwise the ReferenceEquals would have returned false). And so there is no "slightly more optimal" to be expected either. – H H Jun 02 '15 at 17:59
  • 1
    I think the interesting bit about this question is really what is defined as *required behaviour* by the C# spec, and what is just implementation detail in some version of some runtime. To me, string interning feels like an optimization, and thus an implementation detail. In a runtime without interning, each `""` would be a new string, and none of them would be the same as String.Empty? – Anders Forsgren Jun 02 '15 at 17:59
  • @AndersForsgren - you might actually be right, and that makes the question quite a bit more interesting. – H H Jun 02 '15 at 18:17
  • @HenkHolterman What is the required behavior then at runtime for the string objects created through stringbuilder that have nothing appended to them. Wouldn't they be equivalent to `""`? – Adam Jun 02 '15 at 18:33
  • 1
    Introducing a StringBuilder only confuses the issue. But there simply is no "required behaviour" here. See the quote in my answer, RefEquals is only reliable when you Intern() yourself. – H H Jun 02 '15 at 18:43
  • I'm just trying to expand this to answer the OP's question because I feel as though we are getting slightly off-topic to actually answer his question. – Adam Jun 02 '15 at 19:01
  • In any case it is important to distinguish between what is documented behavior and what the current implementation does. One should rely on documented behavior, not on current implementation (unless one explicitly knows about this distinction and have made an informed decision). – Lasse V. Karlsen Jun 05 '15 at 08:34
-1

Since some people already commented about what the CLR does/doesn't and object.RefereceEquals, I will provide two more input data.

  1. Performance wise, there is no significant difference whatsoever. I used this code to test it:

    Sample Code:

    public class StringsTest
    {
    private int i, maxValue = 500000000;
    string myString = "test";
    
    public long CompareToEmptyQuotes()
    {
        Stopwatch sw = Stopwatch.StartNew();
        sw.Start();
    
        for (i = 0; i < maxValue; i++)
        {
            if (myString == "")
            {
                ;
            }
        }
    
        sw.Stop();
        Debug.WriteLine("Elpased Time: {0}", sw.ElapsedMilliseconds);
        return sw.ElapsedMilliseconds;
    }
    
    public long CompareToEmptyString()
    {
        Stopwatch sw = Stopwatch.StartNew();
        sw.Start();
    
        for (i = 0; i < maxValue; i++)
        {
            if (myString == string.Empty)
            {
                ;
            }
        }
    
        sw.Stop();
        Debug.WriteLine("Elpased Time: {0}", sw.ElapsedMilliseconds);
        return sw.ElapsedMilliseconds;
    }
    }
    
  2. With regard to the generated code, this is how the MSIL looks like:

Use of "" generates: IL_001e: ldstr ""

Use of string.Empty generates: IL_001e: ldsfld string [mscorlib]System.String::Empty

This question here expands on the difference (or equality) between ldstr and ldsfld.

Community
  • 1
  • 1
alexandergs
  • 182
  • 2
  • 12
  • I don't understand why I got -2 points. If it is because the answer was ALSO somewhere else, then, nobody should get credit since all the answers are out there somewhere! – alexandergs Jun 02 '15 at 19:31
  • 1
    @Stephen Kennedy, I appreciate your feedback and I have to admit that you are correct in all your appreciations and comments. Even though I had the understanding of what I was trying to say, I did not support my answer very well. Since some people already commented about the CLR and the ReferenceEquals, I will edit my answer to, at least, provide more data for the people to make decisions. Thank you! – alexandergs Jun 04 '15 at 00:28
  • You now have a benchmark without results. Also that code looks like the compiler might optimize the relevant part away. – H H Jun 04 '15 at 06:55
  • Thank you Henk for your valuable feedback!I did not post any results because as I said there was no significant difference between the two. I appreciate your feedback and I will take it into account for my future interventions. – alexandergs Jun 04 '15 at 15:01