The Classy Cast
Article Index
The Classy Cast
Solution

This C# puzzle brings out the differences between static and dynamic typing. Read it, see if you can solve it, and decide which approach to avoiding the problem fits in with your view of object-oriented programming.

 

Banner

 

Background

Object-oriented programming is full of complex pitfalls when you use it in sophisticated ways - even if you think you understand it completely. In this case the problem involves inheritance and type. C# is mostly a strongly statically typed language. In many cases this can be a problem when the idea of type isn't appropriate to a project and dynamic typing would be better. You can adopt dynamic typing to some extent in C# but many programmers prefer to keep static typing in operation using casts if necessary. However there are hidden dangers in trying to be strict.

Puzzle

In this case the project was ideally suited to the application of inheritance in interesting ways. The design started out with a single class that was the base class for everything else. The base class contained everything needed for the basic functioning of the type - but in this example this is reduced to a single property int a:

class myBaseClass
{
public int a;
}

A number of classes were derived from the base class but only two need concern us for this puzzle. the first added some properties and method of its own but for the puzzle let's keep things simple and just have a single additional property int b:

class myClassA : myBaseClass
{
public int b;
}

The second derived class is where the problems begin. It had much of the mechanism of myClassA but it wasn't really a special case of myClassA so it was added as a direct descendant of the base class. Once again all of the mechanism built into the real class is reduced to simple properties - int b which is conceptually the same property as found in myClassA and int c which represents the new functionality of myClassB:

class myClassB : myBaseClass
{
public int b;
public int c;
}

Later on in the project a programmer wrote a simple method that accepted a myClassA object and worked with property b:

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

Again you have to think of the action of displaying the current value of b in a MessageBox and then zeroing it as standing in for some complex processing.

Everything worked fine up to this point and code like:

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

did exactly what was expected. Then another programmer wrote:

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

and immediately got a compile time error as myClassB isn't derived from myClassA and hence isn't automatically cast to a myClassA.  The first attempt at making it work, and it should be possible to make it work as myClassB has a b property was to place an explicit cast infront of the parameter:

myMethod((myClassA)myobject);

Of course this doesn't work because the system doesn' know how to cast a myClassB to a myClassA as myClassB is a sibling rather than a child or myClassA.

Now what?

Well the next step that was taken was to fill in the missing elements and actually implement a custom cast. This is easy and it makes the code already written work. After creating a

static public implicit operator myClassA(
                             myClassB obj)

method as part of myClassB (the details of the implementation are left to the reader - but it isn't difficult to work out)  the original code worked.  That is

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

does display the current value in b.

Job done... but later it was discovered that while the method did implement most of what was required on myClassB there were some strange omissions - it almost worked but not quite. In our example for example, while the MessageBox show the correct value of property b it fails to zero it.

Why?

Turn to the next page when you are ready to find out.

<ASIN:1449380344>

<ASIN:1430225378>
<ASIN:0470447613>

<ASIN:1933988924>