On this page.... RSS 2.0 | Atom 1.0 | CDF
# Friday, April 8, 2005

I just ran into a problem that seems like it shouldn't be a problem, though I'm sure there's a perfectly obscure and valid reason it is.  Consider the following:

public class MyBase
{ // ...}

public class MyChild : MyBase
{ // ...}

public class Foo
{
  public static void Bar()
  {
    MyBase base = GetMyBaseFromSomewhere();
    MyChild child = (MyChild)base;
  }
}

The last line in Bar throws a System.InvalidCastException: Specified cast is not valid.  Why?  It seems to me that since we're guaranteed that MyChild has everything that MyBase has, it should become the child type lacking values only for the new fields that MyChild has defined.

I'm sure there's some completely reasonable computer sciency reason this doesn't work, such as the data is stored on the heap in a structure defined as MyBase that has no knowledge of MyChild, so it can't possibly know how to become MyChild; all the same, I think it should work.  If there is a way to work around this, I'd appreciate knowing about it.

Looks like this is another place where generics could certainly save the day.  We could specify GetMyBaseFromSomewhere<T>() where T: MyBase, new(), and then we could tell it (in the case above) that we want a MyChild instance.

Unfortunately, this app is in 1.1, so that's not an option.  As I see it, the only alternative here would be for me to define a new method like FillMyBaseFromSomewhere(MyBase base), pass a MyChild instance in, and have it populate the MyBase members on MyChild.  Or (worse), I could define a MergeFromBase method that manually copies the fields from MyBase to MyChild.  Am I missing other alternatives?  Maybe serializing as MyBase and deserializing as MyChild would work?  Anyone?

Friday, April 8, 2005 7:28:01 PM (Eastern Daylight Time, UTC-04:00)  #    Disclaimer  |  Comments [6]  | 
Saturday, April 9, 2005 1:56:14 AM (Eastern Daylight Time, UTC-04:00)
You are trying to upcast. This is the warning that you get about casting from say a double to a float - you can always downcast (derived -> base) but OO principles say that a base class should never know anything about their derived classes.

Have you considered using an interface instead? And if so, why wouldn't this approach work in this situation?
Saturday, April 9, 2005 9:39:46 AM (Eastern Daylight Time, UTC-04:00)
Thanks, Christopher. The thing is, I don't really want my base to know about my child. In my mind, the CLR should recognize that the class I'm trying to cast to is derived from the instance and handle setting up a new instance of the child type and perpetuating the fields from the base to the child instance.

Also, I should mention that the example above is completely hypothetical, so the fact that I hastily used the reserved word "base" as my MyBase identifier is peripheral to the problem at hand.
Sunday, April 10, 2005 12:47:21 AM (Eastern Daylight Time, UTC-04:00)
Maybe a "workaround" would be to define a constructor in the derived class that takes a MyBase as an argument. In effect manually doing what you are trying to achieve in the constructor, since I have never heard of something like that being against the "OO rules".

Matter of fact, I think it may be perfectly fitting for a derived class to be able to know about its base class and set its state from an instance of the base.
Tuesday, April 12, 2005 2:57:52 PM (Eastern Daylight Time, UTC-04:00)
Thanks, Christopher. What I ended up doing was using a helper method I wrote that copies the fields from one instance to another using Reflection. Since this happens relatively infrequently, I'm not concerned about the perf hit of reflecting, and it saves development and maintenance time, which are typically more costly anyways.
Tuesday, April 19, 2005 11:53:17 PM (Eastern Daylight Time, UTC-04:00)
Did you try using the "AS" (no pun intended) keyword?
ObjA as ObjB;
Tuesday, April 19, 2005 11:56:48 PM (Eastern Daylight Time, UTC-04:00)
No, using the as operation basically does an attempt to cast and returns null if the cast fails. So in my case, instead of getting the invalid cast exception, I would have gotten a null.
Comments are closed.

Disclaimer
The opinions expressed herein are solely my own personal opinions, founded or unfounded, rational or not, and you can quote me on that.

Thanks to the good folks at dasBlog!

Copyright © 2019 J. Ambrose Little