Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In .Net/C#, is null strongly-typed?

Tags:

c#

.net

Does null have a type? How is a null value represented internally? What is happening in the following code?

void Foo(string bar) {...}
void Foo(object bar) {...}

Foo((string)null);

Edit: The answers so far have been unspecific and too high-level. I understand that a reference type object consists of a pointer on the stack which points to a location on the heap which contains a sync block index, a type handle and the object's fields. When I set an instance of an object to null, where does the pointer on the stack point to, exactly? And in the code snippet, is the cast simply used by the C# compiler to decide which overload to call, and there is not really any casting of null going on?

I am looking for an in-depth answer by someone who understands the CLR internals.

like image 931
Matt Howells Avatar asked Aug 12 '09 11:08

Matt Howells


1 Answers

The cast to string in your code sample doesn't give the null a type, as null cannot have a type itself. If you want proof of this, then execute the following code where you can see that null is always equal to itself, irrespective of what the type of variable it was assigned to is:

string s = null;
IPAddress i = null;
Console.WriteLine(object.Equals(s, i)); // prints "True"
Console.WriteLine(object.ReferenceEquals(s, i)); // prints "True"

What the cast does is tell the compiler which overload to choose. As null doesn't have a type it does not know whether to choose the overload that takes an object or a string as the value could be interpreted as either. So you're helping it out by saying "Here's a null value that should be treated as if it was a string".


If you want to see what's going on underneath, then look at the IL from your code. The relevant bit for the method call is something like the following in textual IL (depending on your namespace and class name, etc):

ldnull 
call void ConsoleApplication1.Program::Foo(string)

So all that's happening is that a null is being loaded on the stack, and then this is consumed by the overload that takes the string, as overload resolution is performed at compile time so the method to call is baked into the IL.

If you want to see what ldnull does, and why it's different from just using something like ldc.i4.0 to load a zero onto the stack then see this answer (if you don't want to follow the link, the reason is that it's a size-agnostic zero which otherwise doesn't exist in the CLR).

like image 192
Greg Beech Avatar answered Sep 22 '22 14:09

Greg Beech