The Classy Cast
Article Index
The Classy Cast
Solution

Solution

This is an example of pragmatic static typing meeting a situation that really calls for dynamic typing. The point is that a myClassB isn't really an instance of a myClassA object in any proper sense. The only way it can be cast to a myClassA object is by an active type converting cast. The only safe casts are passive and simply allow a sub-type to be regarded as a base type with no active conversion needed.

The problem becomes clear as soon as you see the code for the explicit cast operator:

class myClassB : myBaseClass
{
public int b;
public int c;
static public implicit operator myClassA(
myClassB obj)
{
  return new myClassA()
             { a = obj.a, b = obj.b };
 }
}

It can only work by really doing the conversion on the myClassB object into a new myClassA object.

This is fine as long as you are not expecting any changes to the newly generated object to be passed back in some way to the original. That is it b is the property on the new temporary myClassA object then

MessageBox.Show(obj.b.ToString());

will work but

obj.b = 0;

changes the b property on the myClassA temporary object which is deleted as soon as the method ends.

Banner

Pattern

There are so many ways to avoid this problem that it is difficult to know where to start or which point of view to emphasise. It is clear that our fundamental problem is poor inheritance hierarchy which encourages programmers to try and fix it. Perhaps a better and more fundamental approach would have been to take a dynamic point of view and write the method that works with myClassA as:

void myMethod(dynamic obj)
{
MessageBox.Show(obj.b.ToString());
obj.b = 0;
}

In this case there is no need to use a cast to call it with myClassB or indeed any class. The only requirement for this to work is that the instance passed as obj has a b property.

This works but if you want to avoid runtime errors you have to add safeguards against using non-existent properties and methods.

If you want to stay with static typing then you need to stick to the rule that you do not write custom active type converting casts. If you need an active type conversion e.g. a myClassB into a myClassA then write a type conversion constructor:

 

class myClassA : myBaseClass
{
public int b;
public myClassA(myClassB obj)
{
  a = obj.a;
  b = obj.b;
}
}

Now the only way to "cast" the myClassB object is to use the conversion constructor:

 

myClassB myobject = new myClassB() 
                     { a = 10, b = 20 };
myClassA temp = new myClassA(myobject);
myMethod(temp);

and it become immediately obvious that a new object is involved in the conversion. This doesn't exactly solve the problem but it does make it clear to see.

There are almost certainly other approaches to the difficulty and many programmers who would say that you shouldn't ever get into this position by creating an inheritance hierarchy of this sort. There are also programmers who would hold that inheritance hierarchies are a waste of time and if a myClassB object can behave like a myClassA object then let it.

The one clear message is: don't create active type conversion casts unless you really have a very good reason to do so.

Further reading:

Dynamic C# 4

Programming Paradigms for Languages

Late Binding - Myths and Reality

Type Systems Demystified

Strong typing

 

Banner

More Puzzles

Sharpen Your Coding Skills
The Best Sub-Array Problem

At first glance this puzzle seems trivial, all you have to do is find a sub-array, in an array of numbers,  that sums to the largest value. It sounds almost too easy to need a solution, let alone [ ... ]


C#
Programmer Puzzle - Class and struct

This C# puzzle shouldn't be difficult as long as you are secure in your understanding of class and structs. See if you can spot the danger as soon as you read it.


C#
In-Place Or Operator Methods?

This particular C# puzzle is one of those that involves an error that no self respecting programmer would make... but are you so sure. If you use the DateTime class regularly then sure, you not only w [ ... ]


Other Articles


<ASIN:0321637003>

<ASIN:0596800959>

<ASIN:047043452X>

<ASIN:0123745144>