133

This is valid C# code

var bob = "abc" + null + null + null + "123";  // abc123

This is not valid C# code

var wtf = null.ToString(); // compiler error

Why is the first statement valid?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
superlogical
  • 14,332
  • 9
  • 66
  • 76
  • 103
    I find it peculiar that your `null.ToString()` is given the name `wtf`. Why does that surprise you? You can't call an instance method when you have nothing to call it from in the first place. – BoltClock May 30 '12 at 10:19
  • 13
    @BoltClock: Of course it is possible calling an instance method on a null instance. Just not possible in C#, but very valid on the CLR :) – leppie May 30 '12 at 11:30
  • 1
    The answers with regard to String.Concat are ***almost*** correct. In fact, the specific example in the question is one of **constant folding**, and the nulls in the first line are eliminated by the compiler- i.e. they are never evaluated at runtime because they don't exist anymore- the compiler has erased them. I wrote a little monologue on all of the rules for concatenation and constant folding of Strings over here for more info: http://stackoverflow.com/questions/9132338/how-many-string-objects-will-be-created-when-using-a-plus-sign/9132374#9132374. – Chris Shain May 30 '12 at 14:49
  • 83
    you can add nothing to a string but you cant make a string out of nothing. – raddrick May 30 '12 at 16:03
  • Is the second statement not valid? `class null_extension { String ToString( Object this arg ) { return ToString(arg); } }` – ctrl-alt-delor May 31 '12 at 14:05

11 Answers11

168

The reason for first one working:

From MSDN:

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.

More information on the + binary operator:

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.

The reason of the error in second is:

null (C# Reference) - The null keyword is a literal that represents a null reference, one that does not refer to any object. null is the default value of reference-type variables.

Community
  • 1
  • 1
Pranay Rana
  • 175,020
  • 35
  • 237
  • 263
  • 1
    Would this work then? var `wtf = ((String)null).ToString();` I'm working in Java recently where casting null's is possible, has been a while since I worked with C#. – Jochem May 30 '12 at 13:56
  • 15
    @Jochem: You're still trying to call a method on a null object, so I'm guessing no. Think of it as `null.ToString()` vs `ToString(null)`. – Svish May 30 '12 at 14:31
  • @Svish yes, now I think of it again, it is a null object, so you're right, it won't work. It wouldn't in Java neither: null pointer exception. Never mind. Tnx for your reply! [edit: tested it in Java: NullPointerException. With the difference that with cast it compiles, without cast it doesn't]. – Jochem May 30 '12 at 14:38
  • generally there is no reason to intentionally concat or ToString the null keyword. If you need an empty string use string.Empty. if you need to check if a string variable is null you can either use (myString == null) or string.IsNullOrEmpty(myString). Alternatively to transform a null string variable into string.Empty use myNewString = (myString == null ?? string.Empty) – csauve May 30 '12 at 15:26
  • @Jochem casting it will make it compile but it will indeed throw a NullReferenceException at runtime – jeroenh May 30 '12 at 21:40
  • So *why* does string concatenation work this way? It seems to me this would be likely to mask errors. – Keith Thompson May 31 '12 at 15:10
  • Wouldn't the `+` operator be overloaded to use the `String.Concat()` function? If so, then it would be possible to treat `null` as `String.Empty`, correct? – IAbstract Jun 05 '12 at 18:33
111

Because the + operator in C# internally translates to String.Concat, which is a static method. And this method happens to treat null like an empty string. If you look at the source of String.Concat in Reflector, you'll see it:

// while looping through the parameters
strArray[i] = (str == null) ? Empty : str;
// then concatenate that string array

(MSDN mentions it, too: http://msdn.microsoft.com/en-us/library/k9c94ey1.aspx)

On the other hand, ToString() is an instance method, which you cannot call on null (what type should be used for null?).

Botz3000
  • 39,020
  • 8
  • 103
  • 127
  • 2
    There is no + operator in the String class though.. So is it the compiler translating to String.Concat? – superlogical May 30 '12 at 10:25
  • @superlogical Yes, that is what the compiler does. So actually, the `+` operator on strings in C# is just syntactic sugar for `String.Concat`. – Botz3000 May 30 '12 at 10:28
  • Adding to that: The compiler automatically picks the overload of Concat that makes most sense. Available overloads are 1, 2 or 3 object parameters, 4 object parameters + `__arglist` and a `params` object array version. – Wormbo May 30 '12 at 17:20
  • What string array is being modified there? Does `Concat` always create a new array of non-null strings even when given an array of non-null strings, or is something else going on? – supercat Apr 09 '15 at 18:25
  • @supercat The modified array is a new array, which is then passed to a private helper method. You can look at the code yourself using reflector. – Botz3000 Apr 13 '15 at 09:35
30

The first sample will be translated into:

var bob = String.Concat("abc123", null, null, null, "abs123");

The Concat method checks input and translate null as an empty string

The second sample will be translated into:

var wtf = ((object)null).ToString();

So a null reference exception will be generated here

Viacheslav Smityukh
  • 5,652
  • 4
  • 24
  • 42
11

The first part of your code is just treated like that in String.Concat,

which is what the C# compiler calls when you add strings. "abc" + null gets translated to String.Concat("abc", null),

and internally, that method replaces null with String.Empty. So, that's why your first part of code does not throw any exception. it is just like

var bob = "abc" + string.Empty + string.Empty + string.Empty + "123";  //abc123

And in 2nd part of your code throws exception because 'null' is not an object, the null keyword is a literal that represents a null reference, one that does not refer to any object. null is the default value of reference-type variables.

And 'ToString()' is a method that can be called by an instance of an object but not any literal.

Talha
  • 18,898
  • 8
  • 49
  • 66
  • 3
    `String.Empty` is not equal to `null`. It's just treated the same way in some methods like `String.Concat`. For example, if you have a string variable set to `null`, C# won't replace it with `String.Empty` if you try to call a method on it. – Botz3000 May 30 '12 at 10:32
  • 3
    Almost. `null` is not treated like `String.Empty` by C#, it's just treated like that in `String.Concat`, which is what the C# compiler calls when you add strings. `"abc" + null` gets translated to `String.Concat("abc", null)`, and internally, that method replaces `null` with `String.Empty`. The second part is completely correct. – Botz3000 May 30 '12 at 11:13
9

In the COM framework which preceded .net, it was necessary for any routine which received a string to free it when it was done with it. Because it was very common for empty strings to be passed into and out of routines, and because attempting to "free" a null pointer was defined as a legitimate do-nothing operation, Microsoft decided to have a null string pointer represent an empty string.

To allow for some compatibility with COM, many routines in .net will interpret a null object as a legal representation as an empty string. With a couple of slight changes .net and its languages (most notably allowing instance members to indicate "do not invoke as virtual"), Microsoft could have made null objects of declared type String behave even more like empty strings. If Microsoft had done that, it would have also had to make Nullable<T> work somewhat differently (so as to allow Nullable<String>--something they should IMHO have done anyway) and/or define a NullableString type which would be mostly interchangeable with String, but which would not regard a null as a valid empty string.

As it is, there are some contexts in which a null will be regarded as a legitimate empty string and others in which it won't. Not a terribly helpful situation, but one which programmers should be aware of. In general, expressions of the form stringValue.someMember will fail if stringValue is null, but most framework methods and operators which accept strings as parameters will regard null as an empty string.

supercat
  • 77,689
  • 9
  • 166
  • 211
5

'+' is an infix operator. Like any operator it is really calling a method. You could imagine a the non-infix version "wow".Plus(null) == "wow"

The implementer has decided on something like this...

class String
{
  ...
  String Plus(ending)
  {
     if(ending == null) return this;
     ...
  }
} 

So.. your example becomes

var bob = "abc".Plus(null).Plus(null).Plus(null).Plus("123");  // abc123

which is the same as

var bob = "abc".Plus("123");  // abc123

At no point does null become a string. So null.ToString() is no different that null.VoteMyAnswer(). ;)

Nigel Thorne
  • 21,158
  • 3
  • 35
  • 51
  • Really, it's more like `var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");`. Operator overloads are static methods at their heart: http://msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Were they not, `var bob = null + "abc";` or especially `string bob = null + null;` would not be valid. – Ben Mosher Jun 05 '12 at 18:18
  • You're right, I just felt I would be too confusing if I explain it that way. – Nigel Thorne Jun 08 '12 at 12:32
3

I guess because it's a literal which doesn't refer to any object. ToString() needs an object.

Pranay Rana
  • 175,020
  • 35
  • 237
  • 263
Saeed Neamati
  • 35,341
  • 41
  • 136
  • 188
2

Adding null to a string is simply ignored. null (in your second example) isn't an instance of any object, so it doesn't even have a ToString() method. It's just a literal.

Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139
2

Someone said in this discussion thread that you can't make a string out of nothing. (which is a nice phrase as I think). But yes - you can :-), as the following example shows:

var x = null + (string)null;     
var wtf = x.ToString();

works fine and does not throw an exception at all. The only difference is that you need to cast one of the nulls into a string - if you remove the (string) cast, then the example still compiles, but throws a run-time exception: "Operator '+' is ambiguous on operands of type '<null>' and '<null>'".

N.B. In the code example above, the value of x is not null as you might expect, it is actually an empty string after you have casted one of the operands into a string.

Slightly different is var a = ((string)null).ToString(); - which compiles but will throw a NullReferenceException. In this case the exception is thrown because the . operator isn't allowed on null values. Using ?. would work here (but ToString isn't executed in this case). The compiler will correctly "create" the variable a as a string.


Another interesting fact is that in C# / .NET the way null is treated is not always the same if you regard different data types. For example:

int? x = 1;  //  string x = "1";
x = x + null + null;
Console.WriteLine((x==null) ? "<null>" : x.ToString());

Regard the 1st line of the code snippet: If x is a nullable integer variable (i.e. int?) containing value 1, then you're getting the result <null> back. If it is a string (as shown in the comment) with value "1", then you're getting "1" back rather than <null>.

N.B. Also interesting: If you're using var x = 1; for the first line, then you're getting a runtime error. Why? Because the assignment will turn the variable x into the datatype int, which is not nullable. The compiler does not assume int? here, and hence fails in the 2nd line where null is added.

Matt
  • 25,467
  • 18
  • 120
  • 187
1

Because there is no difference between string.Empty and null when you concat strings. You can pass null into string.Format as well. But you are trying to call a method on null, which would always result in a NullReferenceException and therefore generates a compiler error.
If for some reason you really want to do it, you could write an extension method, that checks for null and then returns string.Empty. But an extension like that should only be used when absolutly necessary (in my opinion).

Botz3000
  • 39,020
  • 8
  • 103
  • 127
Franky
  • 651
  • 3
  • 11
0

As general: It may or may not valid accepting null as a parameter depending on specification, but it is always invalid to call a method on null.


That's and other topic why the + operator's operands can be null in case of strings. This is kinda VB thing (sorry guys) to make programmers life easier, or supposing the programmer can not deal with nulls. I completely disagree this specification. 'unknown' + 'anything' should be still 'unknown'...

g.pickardou
  • 32,346
  • 36
  • 123
  • 268