D.AhmedRafik D.AhmedRafik - 2 months ago 18
C# Question

Upcasting & Downcasting in C#

Consider we are having three classes, Shape which is the base class and two other classes Circle and Text that inherits from the base classe (Shape)

Shape.cs

namespace ObjectOriented
{
public class Shape
{
public int Height { get; set; }
public int Width { get; set; }
public int X { get; set; }
public int Y { get; set; }

public void Draw()
{

}
}
}


Text.cs

using System;

namespace ObjectOriented
{
public class Text : Shape
{
public string FontType { get; set; }
public int FontSize { get; set; }

public void Weirdo()
{
Console.WriteLine("Weird stuff");
}

}
}


Circle.cs

namespace ObjectOriented
{
public class Circle : Shape
{

}
}


we all know that Upcasting always succeed and that we create a reference to a base class from a subclass reference

Text txt = new Text();
Shape shape = txt //upcast


and downcasting may throw and InvalidCastException for example

Text txt = new Text();
Shape shape = txt; //upcast
Circle c = (Circle)shape; //DownCast InvalidCastException


what i'm confused about is that what are the situations/cases that we might need to up/down cast and object ?

Answer

Normally you use upcasting for objects that are stored in, for example, a list. (shared base type, even Object could be used)

List<Shape> shapes = new List<Shape>();

shapes.Add((Shape)new Text());    // <-- the upcast is done automatically
shapes.Add(new Circle());

When downcasting, you need to check if it's the right type:

foreach(Shape shape in shapes)
{
    if(shape is Circle)
    {
        Circle circle = (Circle)shape;
        // do something..
    }

}

One thing is, Circle and Text are both Shape, but you cannot cast a Circle to a Text. This is because both classes are extending the Shape class and adds different functionality/properties.

For example: A Car and a Bike share their same base Vihicle (a thing used for transporting people or goods, especially on land), but a Bike extends the Vihicle with a saddle and a Car extends the vihicle with, for example, a motor. Therefor they cannot be 'casted' to each other, but both can be seen as a Vihicle.


There are usefull extension methods for this, which handles the type check:

foreach(Circle circle in shapes.OfType<Circle>())
{
    // only shapes of type Circle are iterated.
}

'Real world' example:

If you have a Window, there are many controls on it. Like Labels/Buttons/ListViews/etc. All these controls are stored in a collection of their base types.

For example WPF controls: All child controls (in a FrameWorkElement) are stored in a UIElementCollection. So all controls added as child must be derived from UIElement.

When you are iterating all child controls, (UIElement's) and searching for example a Label, you'll have to check it's type:

foreach(UIElement element in this.Children)
{
    if(element is Label)
    {
        Label myLabel = (Label)element;
        myLabel.Content = "Hi there!";
    }
}

This loop will change all labels (within this) to 'Hi there!'.