Why is it Valid to Concatenate Null Strings but not to Call "null.ToString()"?

C#.NetStringNull

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

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?).

Solution 3 - C#

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

Solution 4 - C#

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.

Solution 5 - C#

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.

Solution 6 - C#

'+' 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(). ;)

Solution 7 - C#

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

Solution 8 - C#

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.

Solution 9 - C#

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.

Solution 10 - C#

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).

Solution 11 - C#

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'...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsuperlogicalView Question on Stackoverflow
Solution 1 - C#Pranay RanaView Answer on Stackoverflow
Solution 2 - C#Botz3000View Answer on Stackoverflow
Solution 3 - C#Viacheslav SmityukhView Answer on Stackoverflow
Solution 4 - C#TalhaView Answer on Stackoverflow
Solution 5 - C#supercatView Answer on Stackoverflow
Solution 6 - C#Nigel ThorneView Answer on Stackoverflow
Solution 7 - C#Saeed NeamatiView Answer on Stackoverflow
Solution 8 - C#Thorsten DittmarView Answer on Stackoverflow
Solution 9 - C#MattView Answer on Stackoverflow
Solution 10 - C#FrankyView Answer on Stackoverflow
Solution 11 - C#g.pickardouView Answer on Stackoverflow