Search code examples
c#downcast

Confusing about downcast in c#


I have two classes:

public class Asset {  }

public class Stock : Asset 
{
    ...
}

When I write:

Stock m = new Stock ();
Asset а = m;             
Stock s = (Stock) а; 

Everything works fine!

But when I write in this way:

Asset а = new Asset();             
Stock s = (Stock) а;

result is InvalidCastException, why?


Solution

  • In your first instance, a is a reference of type Asset, but it's referring to an object whose actual runtime type is Stock.

    Stock m = new Stock ();
    Asset а = m;             
    Stock s = (Stock) а; 
    

    m, a, and s are all different references to the same actual object, whose type is Stock.

    Here, the actual object not a Stock. It's just an Asset:

    Asset а = new Assert();             
    Stock s = (Stock) а;
    

    Because a Stock inherits from Asset, it is a superset of Asset. You can pretend a Stock is an Asset and that's fine, because Stock is, in part, an Asset -- plus whatever else it adds on its own. Naturally, that doesn't cut both ways: An Asset doesn't have all the stuff Stock has, so you can't treat it as if it were a Stock.

    Your assignment to a in the first example didn't change the object into an Asset, or create a new Asset and assign it to m. It was still the same object.

    The type of the reference is only part of the story.

    Try this:

    Stock m = new Stock ();
    Asset а = m;             
    
    //  This will print "Stock" -- it's still that same actual Stock object. 
    Console.WriteLine(a.GetType());
    
    Stock s = (Stock) а; 
    

    Classes are "reference types". They exist on "the heap", out in the darkness somewhere, and you only ever manipulate references to them. Integers and doubles are different. They're "value types":

    int n = 4;
    double d = (double)n;
    

    That code actually creates a new double, equal to 4.0. d doesn't "refer to" n; it is its own, different value. That's very different from how reference types work.

    This stuff is a fundamental feature of the .NET type system. A struct (for example DateTime) is also a value type.