views:

228

answers:

5

Why doesnt this throw an exception dont understand, obj is null

object obj = null;
Console.WriteLine("Hello World " + obj);
+21  A: 

This compiles to

Console.WriteLine(String.Concat("Hello World ", obj));

The String.Concat method ignores null parameters.

It's defined like this: (From the .Net reference source)

    public static String Concat(Object arg0, Object arg1) {
        if (arg0==null) {
            arg0 = String.Empty; 
        }

        if (arg1==null) { 
            arg1 = String.Empty;
        } 
        return Concat(arg0.ToString(), arg1.ToString());
    }

I don't know why it doesn't simply return arg1.ToString() if arg0==null.

The String.Concat(string, string) method is defined like this:

    public static String Concat(String str0, String str1) { 
        if (IsNullOrEmpty(str0)) { 
            if (IsNullOrEmpty(str1)) {
                return String.Empty; 
            }
            return str1;
        }

        if (IsNullOrEmpty(str1)) {
            return str0; 
        } 

        int str0Length = str0.Length; 

        String result = FastAllocateString(str0Length + str1.Length);

        FillStringChecked(result, 0,        str0); 
        FillStringChecked(result, str0Length, str1);

        return result; 
    }
SLaks
It doesn't return arg1.ToString() if arg0==null, because arg1 may also be null, which would cause an exception. The double checking is handled in the string version of ConCat, so all we're losing is one method invocation.
James Curran
@James: It could do an extra `null` check and `return String.Empty` immediately. We're also losing extra `String.Empty` calls. (Although they're probably inlined by the JITter)
SLaks
A: 

If you have an issue where this might occur in a real application, you could always check for null before displaying the text. Then, you could display an alternate text, or nothing.

DOK
On a side note, the null-coalescing operator `??` is extremely handy for this: http://msdn.microsoft.com/en-us/library/ms173224.aspx
Dan Bryant
@Dan Bryant Nice enhancement.
DOK
+3  A: 

Passing a null parameter to a method is not necessarily going to throw an exception; that's up to the implementation of the method (and in that case you'd probably see an ArgumentNullException).

Attempting to access a member* of a null object** is what will always throw a NullReferenceException, guaranteed***.

So...

May or may not throw an exception

object obj = null;
SomeMethod(obj); // passing as parameter

Will definitely throw an exception

object obj = null;
int hashCode = obj.GetHashCode(); // calling instance method

In the case of the code in question, the parameter you are passing to Console.WriteLine is actually the result of a compiled call to string.Concat, which allows null values to be passed as parameters and essentially ignores them -- as SLaks already pointed out.


*Extension methods are a different matter; they can be called on "null" parameters; but since these only present the illusion of acting like instance methods, this rule does not apply to them. In fact, extension methods are after all just static methods. If you call one "on" a null value, you are effectively passing null as a parameter.

**Here I am not including Nullable<T> values with HasValue == false; though these might conveniently be treated as null in many cases, this is just for syntactical convenience: they are no more null than any other value type can ever be null.

***I'm talking about C# here. As SLaks points out in a comment, this is not a rule of the CLI itself. But all instance method calls in C# are compiled to callvirt instructions in IL, which will throw an exception if the instance is null.

Dan Tao
Not always. `Int? obj = null; obj.GetHashCode()` returns `0`.
SLaks
@SLaks: Well, you could say that. But you and I both know that the `null` in `int? obj = null;` is not really `null`.
Dan Tao
Nitpick: Although it's impossible in C#, a `call` instruction can also call a method on a null reference without throwing an exception (unless the method uses `this`)
SLaks
Just to add a further wrinkle, extension methods allow expressions that look like a method call on an instance to actually be passing a parameter to a static method and therefore not necessarily throw an exception.
Dan Bryant
@SLaks: Right -- I seem to remember reading that that's why all method calls in C# are compiled to `callvirt` instructions in IL, right? So that calling methods on `null` objects will always throw a `NullReferenceException`? Anyway, we are talking about C# here after all...
Dan Tao
@Dan Bryant: Yes yes, but extension methods do not count as member access! Gah, I need to fix up this answer, it seems ;)
Dan Tao
@Dan Tao, software engineers are always looking for corner cases :)
Dan Bryant
@Dan Bryant: Look at how atrocious my answer looks now with all those horrible footnotes. Damn you and your nitpicking!
Dan Tao
+1 for footnotes
SLaks
Could be worse, the footnotes could have their own footnotes.
Chris Charabaruk
One final nitpick that Mark Gravell pointed out elsewhere is that if you call .GetType() on a `Nullable<T>` with HasValue=false, it actually _will_ throw a NullReferenceException, due to the fact that GetType() can't be overridden and the nullable will box to null before the call.
Dan Bryant
+1  A: 

Because that would be annoying. For most pruposes there is no semantic difference between an empty and a null string.

Jonathan Allen
A: 

Because they implemented String.IsNullOrEmpty and left it to us to figure out how to use it.

Jimmy Hoffa