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

17,666

Solution 1

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

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

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

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

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.

Share:
17,666
superlogical
Author by

superlogical

Developer from New Zealand! C# .Net/Mono MonoTouch/Mono for Android/Xamarin.Mac Objective-C/iOS Git/Mecurial CSS/SASS MongoDB/Redis/SQL Server/Search/RavenDB/CouchDB/TouchDB Javascript/Node/jQuery/Backbone/CoffeeScript/Angularjs Ruby/Ruby on Rails

Updated on June 05, 2022

Comments

  • superlogical
    superlogical almost 2 years

    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?

  • superlogical
    superlogical almost 12 years
    There is no + operator in the String class though.. So is it the compiler translating to String.Concat?
  • Botz3000
    Botz3000 almost 12 years
    @superlogical Yes, that is what the compiler does. So actually, the + operator on strings in C# is just syntactic sugar for String.Concat.
  • Botz3000
    Botz3000 almost 12 years
    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
    Botz3000 almost 12 years
    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.
  • leppie
    leppie almost 12 years
    Actually, a AccessViolationException will be thrown :)
  • leppie
    leppie almost 12 years
    I just did :) ((object)null).ToString() => AccessViolation ((object)1 as string).ToString() => NullReference
  • Viacheslav Smityukh
    Viacheslav Smityukh almost 12 years
    I have got NullReferenceException. DN 4.0
  • leppie
    leppie almost 12 years
    Interesting. When I put ((object)null).ToString() inside a try/catch I get NullReferenceException too.
  • leppie
    leppie almost 12 years
    DOH, my bad! :*( I was using ((string)null).ToString(), and that gives the AccessViolation.
  • Jochem
    Jochem almost 12 years
    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#.
  • Lemon
    Lemon almost 12 years
    @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).
  • Jochem
    Jochem almost 12 years
    @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].
  • cariseldon
    cariseldon almost 12 years
    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)
  • Wormbo
    Wormbo almost 12 years
    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.
  • jeroenh
    jeroenh almost 12 years
    @Ieppie except that doesn't throw AccessViolation either (why would it?) - NullReferenceException here.
  • jeroenh
    jeroenh almost 12 years
    @Jochem casting it will make it compile but it will indeed throw a NullReferenceException at runtime
  • Keith Thompson
    Keith Thompson almost 12 years
    So why does string concatenation work this way? It seems to me this would be likely to mask errors.
  • Ben Mosher
    Ben Mosher almost 12 years
    Really, it's more like var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");. Operator overloads are static methods at their heart: 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.
  • IAbstract
    IAbstract almost 12 years
    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?
  • Nigel Thorne
    Nigel Thorne almost 12 years
    You're right, I just felt I would be too confusing if I explain it that way.
  • supercat
    supercat about 9 years
    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?
  • Botz3000
    Botz3000 about 9 years
    @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.