1 Answer. You can cast null to any source type without preparing any exception. The println method does not throw the null pointer because it first checks whether the object is null or not. If null before it simply prints the string "null".
There's no "memory assigned" to a pointer. A pointer is just an object containing an address. This might be an address of an actually usable object, or it might be invalid. If it's NULL , it's guaranteed to be invalid.
1 Answer. Show activity on this post. According to the documentation (Explicit conversions) you can cast from a base type to a derived type. Since null is a valid value for all reference types, as long as the cast route exists you should be fine.
In IL on this level, null
is just null
. The compiler knew it was null
because that is what you wrote, as such the compiler does not need to call the cast operator at all. Casting null
to an object will just yield null
.
So this is a compile-time "optimization" or simplification if you will.
Since this is legal, to cast null
to another object type, there is neither a warning nor an error reported from this.
Note that apparently the compiler will not do this even thought it may be able to verify that the value being cast is indeed guaranteed to be null
, if it isn't a literal.
Your example:
void Main()
{
var s = (string)null;
GC.KeepAlive(s);
}
IL:
IL_0000: ldnull
IL_0001: stloc.0 // s
IL_0002: ldloc.0 // s
IL_0003: call System.GC.KeepAlive
(I added the call to GC.KeepAlive
to avoid the compiler dropping the entire variable due to it not being used anywhere.)
If I stuff the null
into an object first, with no possibility of it changing:
void Main()
{
object o = null;
var s = (string)o;
GC.KeepAlive(s);
}
IL:
IL_0000: ldnull
IL_0001: stloc.0 // o
IL_0002: ldloc.0 // o
IL_0003: castclass System.String
IL_0008: stloc.1 // s
IL_0009: ldloc.1 // s
IL_000A: call System.GC.KeepAlive
In Java there's at least one case when you need to cast a null
to some type, and that is when using overloaded methods to tell the compiler which method you want to execute (I assume this is the case in C# as well). Since a null
is 0
(or whatever pointer null
represents) no matter what type it is you won't see any difference in the compiled code though (apart from which method was called).
Because the spec says so. See §6.1.5, §6.2 and §7.7.6 of the C# 5 standard. To quote only the relevant parts:
§7.7.6 Cast expressions
A cast-expression of the form
(T)E
, whereT
is a type andE
is a unary-expression, performs an explicit conversion (§6.2) of the value ofE
to typeT
. [... T]he result is the value produced by the explicit conversion.§6.2 Explicit conversions
The following conversions are classified as explicit conversions:
- All implicit conversions.
§6.1.5 Implicit reference conversions
The implicit reference conversions are:
- From the null literal to any reference-type.
Casting of a null is perfectly valid - sometimes it is required when passing arguments to overloaded methods in order to inform the compiler which method is being invoked.
See the following related question:
Casting null as an object?
The point of the cast is to define str
as a String type, so it's less about whether you can cast a null as a Type and more about defining the type of the variable.
Not everything that looks like (SomeType)expression
is really a cast, in C#. Sometimes the expression needs to acquire a type that it didn't have already. Some other examples:
var a = (short)42;
var b = (Func<int, int>)(i => i + 1);
var c = (IConvertible)"Hello";
In each of these cases, one could also have written the type on the left, instead of var
, if one preferred that. But this is not always the case when the expression is a part of a larger expression, say:
CallOverloadedMethod((short)42); // CallOverloadedMethod has another overload that we don't want
var y = b ? x : (IConvertible)"Hello"; // the ?: operator might not be able to figure out the type without this hint
In your example the literal null
has no type in itself. In some cases, like when choosing between many overloads, like when using the ternary ?:
operator, or when declaring a variable with var
syntax, it is necessary to have an expression that is still null
but also carries a type.
Note that overloads also includes operators, for example in:
public static bool operator ==(Giraffe g1, Giraffe g2)
{
if (g1 == (object)null && g2 != (object)null
|| g1 != (object)null && g2 == (object)null)
{
return false;
}
// rest of operator body here ...
}
the (object)null
syntax is used to ensure the user-defined overload of ==
is not called recursively.
Your syntax is correct and there is no specification limitations in c#. These are specification rules:
The implicit reference conversions are:
From any reference-type to object and dynamic.
From any class-type S to any class-type T, provided S is derived from T.
From any class-type S to any interface-type T, provided S implements T.
From any interface-type S to any interface-type T, provided S is derived from T.
From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true: o S and T differ only in element type. In other words, S and T have the same number of dimensions. o Both SE and TE are reference-types. o An implicit reference conversion exists from SE to TE.
From any array-type to System.Array and the interfaces it implements.
From a single-dimensional array type S[] to System.Collections.Generic.IList and its base interfaces, provided that there is an implicit identity or reference conversion from S to T.
From any delegate-type to System.Delegate and the interfaces it implements.
From the null literal to any reference-type.
From any reference-type to a reference-type T if it has an implicit identity or reference conversion to a reference-type T0 and T0 has an identity conversion to T.
From any reference-type to an interface or delegate type T if it has an implicit identity or reference conversion to an interface or delegate type T0 and T0 is variance-convertible (§13.1.3.2) to T.
Implicit conversions involving type parameters that are known to be reference types. See §6.1.10 for more details on implicit conversions involving type parameters. The implicit reference conversions are those conversions between reference-types that can be proven to always succeed, and therefore require no checks at run-time. Reference conversions, implicit or explicit, never change the referential identity of the object being converted. In other words, while a reference conversion may change the type of the reference, it never changes the type or value of the object being referred to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With