tags:

views:

226

answers:

5

Hi, I have 2 classes Test(Base)and Program(child). Now I am facing some problem while downcasting.

        Test t = new Program();// upcasting-works
        Program p = (Program)t;//Downcasting-works
        Program q = (Program)new Test();//Downcasting -throws exception.

I want to know why its throwing exception? May b its very basic, but somehow I am not getting. Is it for that new object?

Thanks.

+6  A: 

Every Square is a Rectangle but not vice versa. Similarly, every instance of a derived class is a valid instance of the base class but not vice versa. In your example, every Program is a Test but not all Tests are Programs.

Mehrdad Afshari
*Note*: To clarify, that doesn't mean you should inherit Square from Rectangle in OOP :) It's just an analogy. Ironically, the analogy is a well known problem in OO design.
Mehrdad Afshari
A: 

Think of it like this, you can cast Program to Test, because Program IS A Test.

You cannot cast Test to Program, because Test is not a Program.

It is ALWAY safe to downcast, to it only safe to upcast when you are sure the object IS of that type.

Needing to upcast is often a code smell, if you find you often need to upcast your objects, there's probably something wrong with your design.

Hope this helps,

EDIT: Is it always safe to downcast?

The act of downcasting is by definition - according to me - where you know the type of the object, and you're casting it lower down it's inheritance tree. e.g. Cat and Dog both inherit from Animal, Oak and Birch both inherit from Tree.

it is ALWAYS safe to do this

public void DoThingWithCat(Cat snuggles)
{
    snuggles.Meow();
    DoThingWithAnimal(snuggles); // this is always OK, because we know 
                                 // the type of snuggles, and we know 
                                 // snuggles is an animal
}

This is an UpCast. It is not safe to do this, also this is a code is a code smell, there is probably something wrong with your object hierarchy if you need to do this.

public void DoSomethingElse(Animal anAnimal)
{
    DoThingWithCat(anAnimal);    // this is NOT always OK, because we
                                 // DO NOT know the type of anAnimal, 
                                 // and it may not be a Cat
}

This is also unsafe, because it's straight casting, not necessarily up casting or down casting

public void DoSomethingDifferent(object anObject)
{
    DoThingWithAnimal(anObject); // this may or may not work, 
                                 // depending on the type passed in, 
                                 // this is a recipe for disaster, 
                                 // because may not be an Animal, 
                                 // it could be a Tree.
}
Binary Worrier
"It is ALWAY safe to downcast, to it only safe to upcast when you are sure the object IS of that type"..are u sure? I think while downcasting we have to b careful as we have to keep in mind the type.Or, am i not getting you?
Wondering
A: 

The problem is: a Test instance isn't a Program. It works in the first case because the instance is created as a Program (on the first line).

With casts, the type of the actual object (not just the variable) is important.

Marc Gravell
A: 

Mehrdad has given the correct answer. Just to make it clearer:

Your Test is not a Program – the opposite is true: Program is-a Test in your case. Therefore, what you're trying to do isn't an upcast and it's not allowed.

Konrad Rudolph
+7  A: 

This is expected behaviour in all OO systems. In short, you cannot downcast to something for which the dynamic type is not matched. In this line:

Program q = (Program)new Test();

You are creating a Test instance - the instance obviously does not match Program since Test does not derive from Program. At runtime, the computer detects this is the case and throws the exception.

On the other hand, you have:

 Test t = new Program();

Here, you are creating a Program instance - the instance matches Test since Program does derive from Test.

Finally, and out of order, you have:

Program p = (Program)t;

In this case, t is a reference to Test, but the underlying type is really Program - at runtime, the computer is able to determine this is the case so the cast is allowed to work.

1800 INFORMATION
+1 Nicely illustrated
Binary Worrier
Here Console.WriteLine(t.GetType()); will return Program.so if Type of t is Program, then why do we need to mention it explicitly,Program p = (Program)t;
Wondering
Because C# wants you to be explicit about the fact that you are doing a cast that is not guaranteed to be safe.
jerryjvl
We might distinguish between what the compiler knows to be true at compile time, and what can be deduced at run time. At compile time, all the compiler really knows is that "t" is a reference to "Test" - maybe through some kind of detailed analysis, it might be able to tell that it could only really be a "Program" but it doesn't actually do this in reality. So we use the cast to tell the compiler to assume that it could be a "Program" despite what it thinks it knows. Then at run time, the cast will succeed, because it really was.
1800 INFORMATION
Thanks 1800 INFORMATION
Wondering