How does appending to a null string work in C#?
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 typestring
. If an operand of string concatenation isnull
, an empty string is substituted. Otherwise, any non-string operand is converted to its string representation by invoking the virtualToString
method inherited from typeobject
. IfToString
returnsnull
, 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.
Related videos on Youtube
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 & 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 & 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, 2022Comments
-
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 over 9 yearsA somewhat unexpected side effect:
string sample = null;
sample += null;
//sample == string.Empty
Then again, I'm not sure what I would have expectednull + null
to be... -
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 theEmpty
string constant. Does seem odd though I agree :)
-
-
Gone Coding over 12 yearsWhere did you get that reference? The "compiler" should have no knowledge of the runtime values. Thanks
-
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 over 12 yearsThanks for the update. Typical that Microsoft's explanation actually makes it more confusing! :)
-
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 over 12 yearsObviously 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 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 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 over 12 years@HiTechMagic: As per the other answer that should not happen. Was optimization on? What version of .NET?
-
leppie over 12 years@HiTechMagic: When using literal
null
, it gets optimized away, as it can :) -
Gone Coding over 12 yearsThe 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 over 12 yearsWhile 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 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 versionstring.Concat(params string[] values)
. -
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 over 12 yearsSorry 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 over 12 yearsI 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é 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 about 7 years@JohanBoule Its in the compiler: ericlippert.com/2013/06/17/…