Casting

Casting

In C#, a cast is used to explicitly convert a value or a reference to a different type. A cast is performed with a cast operator, which is a type enclosed in parentheses, as shown here:

Type T2 newType = (T2)oldType;

Casting isn’t required when you’re assigning a subclass to a base class reference because subclasses can always be substituted for a base class. However, the reverse is not true.

// OK; assignment to base reference.
Animal a = aDog;

// Error; requires a cast.
Dog d = anAnimal;

// Conversion OK with a cast.
Dog d2 = (Dog)anAnimal;

Explicit casting is required in this case because, in general, a client that expects functionality found in a subclass can’t assume that the base class also contains the same functionality. If you’re sure that a reference to a base class is actually a reference to the derived class, a cast will perform the conversion for you. But what if the cast can’t be performed, perhaps because an unexpected subclass has been encountered? Performing a cast is inherently unsafe—any attempt to perform a conversion can fail if the conversion isn’t allowed. When a conversion fails, an InvalidCastException is raised, as shown in this somewhat contrived example, in which a Cat object is passed to a method that was expecting a Dog object:

class Animal
{
    public void Eat()
    {
        Console.WriteLine("Eating");
    }
}

class Cat: Animal
{
    public void ChaseBirds()
    {
        Console.WriteLine("Chasing birds");
    }
}

class Dog: Animal
{
    public void ChaseCars()
    {
        Console.WriteLine("Chasing cars");
    }
}

class TestAnimal
{
    static void ChaseACar(Animal anAnimal)
    {
        Dog d = (Dog)anAnimal;
        d.ChaseCars();
    }

    static void Main()
    {
        Cat c = new Cat();
        ChaseACar(c);
    }
}

To handle invalid cast exceptions, casts that aren’t absolutely safe should provide the necessary exception handling, as shown here:

static void ChaseACar(Animal anAnimal)
{
    try
    {
        Dog d = (Dog)anAnimal;
        d.ChaseCars();
    }
    catch(InvalidCastException badCast)
    {
        // Error-recovery code
    }
}

The compiler can’t, in general, catch invalid casting errors during compilation—these errors can be detected reliably only at runtime. Sometimes raising an exception is too drastic, however; often it’s more appropriate to attempt a conversion and take alternative actions if the conversion fails. In C#, you can attempt a conversion without raising an exception by using the as keyword, as follows:

Dog d = anAnimal as Dog;

Like a cast, as will attempt to convert a source type to a different target type, but unlike a cast, the as keyword won’t raise an exception if the conversion fails. Instead, the reference will be set to null so that the failure is easily detected programmatically.

static void ChaseACar(Animal anAnimal)
{
    Dog d = anAnimal as Dog;
    if(d != null)
        d.ChaseCars();
    else
        Console.WriteLine("Not a dog");
}


Part III: Programming Windows Forms