1

So I'm trying to understand up-casting and down-casting in c#.

My question is, is this diagram correct or am I still missing something? If its incorrect, where can I find a diagram that represents this concept correctly?

Any help is greatly appreciated.

enter image description here

Edit: Firstly I apologize for the confusion, I realize the diagram is not very clear and that I made a mistake in the down-casting one (where circle2 only has access to string Colour, it should have access to all the properties). I'll try and explain better what I was trying to represent.

So, here is the code that would go with it:

        public class Shape 
        {
           public int Width {get;set;}
           public int Height {get;set;}
           public int X {get;set;}
           public int Y {get;set;}
           public void Draw()
           {
             //do something
           }
        }

        public class Circle : Shape 
        {
           public string Colour {get;set;}
        }
        public class Program
        {
            public static void Main(string[] args)
            {
                //Up-casting
                Circle circle = new Circle(); //object is created
                Shape shape = circle; // shape point to circle object

                //Down-casting
                Circle circle2 = (Circle)shape;
            }
        }
7
  • 4
    The code next to diagrams represents upcasting and downcasting. I have no idea what the diagrams themselves are meant to represent.
    – Rotem
    Commented Aug 22, 2017 at 12:58
  • Are the ovals supposed to represent variables, i.e. references to objects? Commented Aug 22, 2017 at 13:00
  • Are the squares meant to represent interfaces, and the cylinders classes implementing those interfaces? Commented Aug 22, 2017 at 13:02
  • Well I'm trying to get my head around the concept of changing and objects reference type. For as far as I can understand, when up-casting, circle of type Circle and shape of type Shape are pointing to the same object/location in memory? And all the properties of shape and circle exist in that object. But have limit access to the properties depending if you're using shape or circle?
    – RRC
    Commented Aug 22, 2017 at 13:06
  • 5
    Casting is not actually changing the type when it comes to classes like this, it only allows you "look at the type in a different way". So upcasting a circle to a shape does not remove all the properties that the Circle type added, nor does downcasting back "put them back in place", they've always been there, it's just that they're hidden from view when you look at the circle through a shape reference. To be honest I didn't understand your diagram. Commented Aug 22, 2017 at 13:08

1 Answer 1

5

You don't need any diagrams, just get the basic facts down right and everything becomes crystal clear.

Up and down casting presupose an order, so lets get that straight first:

In a typical type hierarchy we have the following:

Animal -> Vertebrate -> Mammal -> Feline -> Cat

The higher, or more general, type is Animal and the lowest, or more specific, type is Cat; the order is therefore the "generalness" of the type.

Upcasting is casting to a more general type, and down casting is casting to a more specific type:

  • Up casting : Animal animal = new Cat();
  • Down casting: var feline = (Feline)animal;

Ok, but was is really going on in both "casts"? What changes are done to the objects when we down or up cast? The answer is rather simple; nothing! No changes whatsoever are done to the objects at all.

Both casts are reference conversions which are identity preserving; this means that the object before the cast and after the cast are(is) exactly the same object. As the name implies, the only thing you are changing is the type of the reference pointing to the object; the variables animal and cat.

This is made obvious by doing: ReferenceEquals(animal, feline); which will return true.

Note the upcasting is always implicit, because it is always safe; a Cat is always a Feline which is always a Mammal, etc. Downcasts on the other hand have to be explicit because they are not guaranteed to be safe:

Animal animal = new Dog();
Feline feline = animal; //unsafe, can not implicitly do the conversion

The compiler asks you to perform the cast explicitly, which is a way to tell the compiler "I know what I'm doing, animal is a Feline, trust me.". Of course the compiler will trust you only partially and will still provide runtime guards to make sure the cast is possible or throw a runtime exception if it isn't. In the code above, the cast will obviously fail and you will get a runtime error.

Do note that all this only applies to Reference Types. Value Types, by definition, don't have reference conversions because you can't get a reference to a value type. This is one of the reasons why type variance is not allowed in value types; there are no identity preserving conversions, the only conversions allowed in type variance.

1
  • This tripped me up recently because I didn't expect the object to still contain the, now essentially hidden, fields after casting. For example, Cat c = new Cat(); c.VetName = "John Smith"; If Feline doesn't have a VetName property, then if do Feline f = c; I no longer have access to the VetName field, but it's still there! So I can pass the feline "f" object around and then at a later point do Cat newCatObject = (Cat)f; and I can then print newCatObject.VetName and it will print "John Smith".
    – Ryan
    Commented Apr 5, 2019 at 16:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.