An object reference can be:
An upcast always succeeds; a downcast succeeds only if the object is properly typed.
An upcast operation creates a base class reference from a subclass reference.
For example:
Product myProduct = new Product();
Item a = myProduct; // Upcast
Product
, DiscountProduct
, Item
are all
defined in the previous section.
After the upcast, variable a still references the
same Product
object as variable myProduct
.
The object being referenced is not itself altered or converted:
Console.WriteLine (a == myProduct); // True
Although a and myProduct
refer to the identical object,
a
has a more restrictive view on that object:
Console.WriteLine (a.Name); // OK
Console.WriteLine (a.InStoreCount); // Error: InStoreCount undefined
The last line generates a compile-time error because the variable a is of type Item
,
even though it refers to an object of type Product
.
To get to its InStoreCount
field,
we have to downcast the Item
to a Product
.
A downcast operation creates a subclass reference from a base class reference.
For example:
Product myProduct = new Product();
Item a = myProduct; // Upcast
Product s = (Product)a; // Downcast
Console.WriteLine (s.InStoreCount);
Console.WriteLine (s == a); // True
Console.WriteLine (s == myProduct); // True
As with an upcast, only references are affected-not the underlying object.
A downcast requires an explicit cast because it can potentially fail at runtime:
DiscountProduct h = new DiscountProduct();
Item a = h; // Upcast always succeeds
Product s = (Product)a; // Downcast fails: a is not a Product
If a downcast fails, an InvalidCastException
is thrown.
The as
operator performs a downcast that evaluates to null rather than throwing
an exception if the downcast fails:
Item a = new Item();
Product s = a as Product; // s is null; no exception thrown
This is useful when you're going to subsequently test whether the result is null:
if (s != null) {
Console.WriteLine (s.InStoreCount);
}