Overriding Problems A C# Puzzle
Written by Mike James   
Article Index
Overriding Problems A C# Puzzle
Solution

Objects are indispensable but exactly how a language implements them and makes them available to the programmer matters. Sometimes the class-based approach complete with inheritance makes things complicated. So much so that it is easy to misunderstand and make mistakes.

This C# puzzle isn't particularly unique to the language but it doesn't go out of its way to make this aspect of inheritance easy to understand.

Background

There is a sense in which the background to this puzzle is the whole philosophy of class-based, object-oriented programming. A quick sketch of the idea is that you don't create objects directly. Instead you create a class which is a template for an object and use inheritance. That is you can create derived classes which inherit all the methods and properties of the base class and the  set of derived classes form the type hierarchy. It is also assumed that anywhere you can use a base class you can use a derived class because the derived class is "bigger" than the base class, in the sense it has at least the set of methods and properties of the base class.

That is, if you create class A and then create class B which inherits from class A, then anywhere you use class A you can use a class B because it "contains" a class A.

All this is very reasonable and translates to the C# programmer's knowledge that a variable of a type can reference an object of a derived type.

This means that is there is nothing wrong with:

ClassA myVariable=new ClassB();

as long as ClassB inherits from ClassA.

However, things get tricky when you introduce the need to modify what the derived class inherits. You could forbid modification or overriding and say that any methods and properties ClassB inherits are fixed and cannot be changed. This would result in a simple and safe world but one that would be difficult to work with.

In practice we do allow methods and properties to be redefined in derived classes and this is where our puzzle and many others originate.

Puzzle

As always with a puzzle, the actual details of the code that caused the real problem have been reduced down to the very minimum necessary. This should allow you to see the problem more quickly and without any diversions to waste your time.

One way to work with an array of mixed types is to use the base type. An array of base type elements will also store any derived types. For example, if we define two classes, a Base type and a Derived type which inherits from Base:

public class Base
{
public string MyMethod()
{
return "Base Method";
}
}
public class Derived : Base
{
}

then you can create an array that will store either type:

Base[] myArray = new Base[2];
myArray[0] = new Base();
myArray[1] = new Derived();
foreach (Base element in myArray)
{
MessageBox.Show(element.MyMethod());
}

In this case, as the Derived class doesn't define its own MyMethod, the one inherited from the base class is used and in both cases you see the message "Base Method".

Of course practical considerations lead to MyMethod being modified and the new definition of MyMethod in Derived is:

public class Derived : Base
{
public string MyMethod()
{
return "Derived Method";
}
}

Now when the program is run what the programmer expects to see is that the Base class method is called for Base class elements and the Derived class method is called for Derived class elements.

This is, of course, exactly what doesn't happen.

Despite the redefinition of the method, the Base class method is used both times.

This isn't what is supposed to happen. Object-oriented philosophy demands "polymorphism", which is where the method appropriate for the object is used.

That is, the array element myArray[1] may be of type Base, but it holds an object of type Derived and so it should use the Derived method not the Base method. This is what polymorphism is all about, but it isn't working.

It also doesn't work if you try casting the derived class to the base class.

What is the problem?

Why isn't the object's own method used?

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

Banner

<ASIN:1449380344>

<ASIN:1430225378>
<ASIN:0470447613>

<ASIN:1933988924>