How does appending to a null string work in C#?

14,629

Solution 1

the + operator for strings are just shorthand for string.Concat which simply turns null arguments into empty strings before the concatenation.

Update:

The generalized version of string.Concat:

public static string Concat(params string[] values)
{
    int num = 0;
    if (values == null)
    {
        throw new ArgumentNullException("values");
    }
    string[] array = new string[values.Length];
    for (int i = 0; i < values.Length; i++)
    {
        string text = values[i];
        array[i] = ((text == null) ? string.Empty : text);
        num += array[i].Length;
        if (num < 0)
        {
            throw new OutOfMemoryException();
        }
    }
    return string.ConcatArray(array, num);
}

Solution 2

The relevant citation should be ECMA-334 §14.7.4:

String concatenation:

string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);  

The binary + operator performs string concatenation when one or both operands are of type string. If an operand of string concatenation is null, an empty string is substituted. Otherwise, any non-string operand is converted to its string representation by invoking the virtual ToString method inherited from type object. If ToString returns null, an empty string is substituted.

Solution 3

it is because

In string concatenation operations, the C# compiler treats a null string the same as an empty string, but it does not convert the value of the original null string.

From How to: Concatenate Multiple Strings (C# Programming Guide)

The binary + operator performs string concatenation when one or both operands are of type string. If an operand of string concatenation is null, an empty string is substituted. Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. If ToString returns null, an empty string is substituted.

From Addition operator

Solution 4

Here is what your code gets compiled to

string sample = null;
sample += "test";

is compiled to this IL code:

.entrypoint
  // Code size       16 (0x10)
  .maxstack  2
  .locals init ([0] string sample)
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  ldstr      "test"
  IL_0009:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_000e:  stloc.0
  IL_000f:  ret

And String.Concat takes care of NULL string.

Share:
14,629

Related videos on Youtube

Gone Coding
Author by

Gone Coding

Devoting my spare time to useful projects for a while, so please don't expect any new answers. Been cutting code for well over 40 years now (way back to The Hobbit on the BBC Micro and Way Of The Exploding Fist on the C64! Who remembers those games now?)... no sign of stopping yet. I now use StackOverflow mainly to keep my brain active. I have found answering questions here has improved my jQuery skills more than anything else I have tried. My favorite, most time-consuming and most underrated, answer is here: Silverlight Rotate &amp; Scale a bitmap image to fit within rectangle without cropping unfortunately my hosting company pulled the rug from that hosting so the interactive example is gone :( Did a lot of Silverlight &amp; WPF PRISM work in recent years, then WP7 and Windows 8. Had jQuery jumping through hoops using TypeScript and LESS on highly structured and very large projects using dozens of my own jQuery plugins. FYI: My Avatar is Rincewind the inept magician. I chose him, not because I am also an inept magician (we hope) but, because I was lead developer on Discworld I and II and grew rather fond of him.

Updated on June 06, 2022

Comments

  • Gone Coding
    Gone Coding almost 2 years

    I was surprised to see an example of a string being initialised to null and then having something appended to it in a production environment. It just smelt wrong.

    I was sure it would have thrown a null object exception but this greatly reduced example also works:

    string sample = null;
    sample += "test";
    // sample equals "test"
    

    *Note the original code I found sets a string property to null and appends to it elsewhere so answers involving the compiler optimizing out the null at compile-time are irrelevant.

    Can someone explain why this works without error?

    Follow-up:

    Based on Leppie's answer I used Reflector to see what is inside string.Concat. It is now really obvious why that conversion takes place (no magic at all):

    public static string Concat(string str0, string str1)
    {
        if (IsNullOrEmpty(str0))
        {
            if (IsNullOrEmpty(str1))
            {
                return Empty;
            }
            return str1;
        }
        if (IsNullOrEmpty(str1))
        {
            return str0;
        }
        int length = str0.Length;
        string dest = FastAllocateString(length + str1.Length);
        FillStringChecked(dest, 0, str0);
        FillStringChecked(dest, length, str1);
        return dest;
    }
    

    **Note: the specific implementation I was investigating (in the .Net library by Microsoft) does not convert to empty strings as is suggested by the C# standards and most of the answers, but uses a few tests to shortcut the process. The end result is the same as if it did but there you go :)

    • Timothy
      Timothy over 9 years
      A somewhat unexpected side effect: string sample = null; sample += null; //sample == string.Empty Then again, I'm not sure what I would have expected null + null to be...
    • Gone Coding
      Gone Coding over 9 years
      @Timothy: given the source code for Concat above, that is exactly what I would expect. IsNullOrEmpty == true on both parameters returns the Empty string constant. Does seem odd though I agree :)
  • Gone Coding
    Gone Coding over 12 years
    Where did you get that reference? The "compiler" should have no knowledge of the runtime values. Thanks
  • Gone Coding
    Gone Coding over 12 years
    +1: Thanks for that. Based on your answer I decompiled String.Concat (added above) and it all makes sense now. Cheers.
  • Gone Coding
    Gone Coding over 12 years
    Thanks for the update. Typical that Microsoft's explanation actually makes it more confusing! :)
  • Random832
    Random832 over 12 years
    @HiTech Magic The compiler does do concatenation of constant values (string literals and the null literal), replacing the concatenation expression with a string literal of the whole string. It also eliminates null literals from concatenation expressions.
  • KeithS
    KeithS over 12 years
    Obviously this is the right answer for the OP, but was it ever true in .NET that "abc" + null == null? Classically, null is a "non-value", and so operations on a generic "null" are inconclusive. I was always taught that "null isn't empty", and by definition this is correct; null != String.Empty, which is why we have String.IsNullOrEmpty().
  • Andy
    Andy over 12 years
    @KeithS, this is simply because the + operator for a string is defined as syntatic sugar to call string.Concat. If you remove the +operator definition on string, you wouldn't be able to use + at all. So its not like addition is defined for everything and the compiler magically figures it out (as some languages do). C# requires an explicit +operator definition to use the operator.
  • KeithS
    KeithS over 12 years
    @Andy: That wasn't the answer to the question I asked. The question was, did .NET's string concatenation ever behave differently than it does currently?
  • leppie
    leppie over 12 years
    @HiTechMagic: As per the other answer that should not happen. Was optimization on? What version of .NET?
  • leppie
    leppie over 12 years
    @HiTechMagic: When using literal null, it gets optimized away, as it can :)
  • Gone Coding
    Gone Coding over 12 years
    The example is greatly simplified. The actual situation had the null assignment to a member in a constructor, and the += happens much later, so optimisation is not a factor. Thanks anyway
  • Gone Coding
    Gone Coding over 12 years
    While that was the aim of the language it appears the MS coders were happy to write their logic based on null-ness of the parameters instead (see the decomp above). I guess they felt it was more optimal.
  • leppie
    leppie over 12 years
    @HiTechMagic: I think there is a misunderstanding issue here. You should not concern yourself with the internals of string.Concat. The way I specified it, is how it behaves. And that is indeed how it is implemented in the generalized version string.Concat(params string[] values).
  • Rasmus Faber
    Rasmus Faber over 12 years
    @HiTech Magic: I believe the implementation matches the specification. Note the text I emphasized: "If an operand [..] is null, an empty string is substituted". Exactly what we see in the behavior and the decompilation.
  • Gone Coding
    Gone Coding over 12 years
    Sorry I must be missreading the decomp, as at no point does it substitute empty strings. The end result is the same as if it did, and I realise I am just being pedantic, but there you go. Thanks
  • Gone Coding
    Gone Coding over 12 years
    I realise I was being pedantic (and that leaving out the .Net tag was a big mistake) :) I will edit my question for clarity. Thanks.
  • Johan Boulé
    Johan Boulé about 7 years
    @Andy Actually, where is the explicit definition of operator+ or operator+= in C# ? People have commented that "+=" is a magical syntactic sugar for string.Concat. I can't help but contrast this with C++'s std::string which explicitly defines all operators for strings, since string isn't a fundamental type in that language.
  • Andy
    Andy about 7 years
    @JohanBoule Its in the compiler: ericlippert.com/2013/06/17/…