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.
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;
}
}
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:
The higher, or more general, type is
Animal
and the lowest, or more specific, type isCat
; 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:
Animal animal = new Cat();
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
andcat
.This is made obvious by doing:
ReferenceEquals(animal, feline);
which will returntrue
.Note the upcasting is always implicit, because it is always safe; a
Cat
is always aFeline
which is always aMammal
, etc. Downcasts on the other hand have to be explicit because they are not guaranteed to be safe: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 aFeline
, 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.