Wednesday, December 12, 2012

[C#] Polymorphism: Exploring upcast references retaining data from child upon downcast

class Parent {}

class Child1: Parent {
    public int childInt;
}

class Child2: Parent {}

class Child3: Parent {
    public int childInt;
}

static void Main(string[] args) {
    var p = new Parent();
    var c1 = new Child1();

    c1.childInt = 5;
    p = c1; //Upcast
    c1 = (Child1) p; //Downcast
    //p.childInt not possible
    Console.WriteLine(c1.childInt); //5       

    var c2 = new Child2();
    //c2 = (Child2)p; this is legal but fails at runtime

    var c3 = new Child3();
    //c3 = (Child3)p; this is legal but fails at runtime

    c3 = p as Child3;
    if(c3 == null) //true
       Console.WriteLine("null"); 
}
It would seem logical if the Parent instance lost the data from the Child upon conversion, but there is actually no conversion going on. It's only a reference.
Since we deal with a reference, p simply points to c1 - but p is not exposing the childInt field.

Now, c1 = p forces a cast since we may have other child-classes, say Child2, and Child2 might not have the fields we require. It could potentially fail at runtime (where p = c1 will never fail because upcasts cannot).

And, as we see in the commented code, c1 will have retained it's value. Makes sense when you think about it, since it's all references, but it may not seem obvious at first.

Interesting to note is that if we cast p to an identical class to Child1 with the same fields, Child3, it also fails.

If you really wanted to do an unsafe downcast, you can use the as operator. But if the conversion fails, it will default to null. This is because as has no idea how to convert our objects.

No comments:

Post a Comment