views:

2548

answers:

5

I have a base class with a virtual method, and multiple subclasses that override that method.

When I encounter one of those subclasses, I would like to call the overridden method, but without knowledge of the subclass. I can think of ugly ways to do this (check a value and cast it), but it seems like there should be an in-language way to do it. I want the List to contain multiple subclasses within the same list, otherwise obviously I could just make a List.

EDIT: Fixed the comment in the code that was wrong, which lead to the very appropriate first answer I got :)

For instance:

Class Foo 
{
    public virtual printMe()
    {
        Console.Writeline("FOO");
    }
}

Class Bar : Foo 
{
    public override printMe()
    {
        Console.Writeline("BAR");
    }
}

List<Foo> list = new List<Foo>();
// then populate this list with various 'Bar' and other overriden Foos

foreach (Foo foo in list) 
{
    foo.printMe(); // prints FOO.. Would like it to print BAR
}
A: 

Why should it print "Foo"? That is not the purpose of virtual methods. The whole point is that the derived classes can change the way the function works without changing the interface. A Foo object will print "Foo" and a Bar object will print "Bar". Anything else would be wrong.

Ed Swangren
You're absolutely right. I had a bug in the comment in the snippet that I originally posted. It's calling the base class method, presumably because it doesn't know that it's a subclassed instance.
John Noonan
A: 

Use the new modifier to explicitly hide a member inherited from a base class. To hide an inherited member, declare it in the derived class using the same name, and modify it with the new modifier. This will result in exactly the behavior you want.

For more info go here: http://geekswithblogs.net/Mohamed/articles/28613.aspx

Manu
+2  A: 
class Foo 
{
    public virtual void virtualPrintMe()
    {
        nonVirtualPrintMe();
    }

    public void nonVirtualPrintMe()
    {
        Console.Writeline("FOO");
    }
}

class Bar : Foo 
{
    public override void virtualPrintMe()
    {
        Console.Writeline("BAR");
    }
}

List<Foo> list = new List<Foo>();
// then populate this list with various 'Bar' and other overriden Foos

foreach (Foo foo in list) 
{
    foo.virtualPrintMe(); // prints BAR or FOO
    foo.nonVirtualPrintMe(); // always prints FOO
}
Daniel Earwicker
This is the behavior I wanted but wasn't getting.. My problem turned out to be loading old serialized objects that were of the old base class type, rather than the new subclass.
John Noonan
A: 

To get the behavior you want in this situation you could remove the virtual on the base class and use new on the subclass.

However, like Ed Swangren indicated, why would you?

Jeremy Wilde
A: 

Isn't there a solution where you just cast the object you want to call the other one:

 foo.printMe(); // prints FOO.. Would like it to print BAR

becomes

(Foo)foo.printMe(); // foo can be any derived class of Foo.

Or am I missing some part of the question?

JB King
That second one would call printMe and try to cast the return value to (Foo). And it returns void.
Daniel Earwicker
Ah,sorry I missed a set of brackets, the second line should be ((Foo)foo).printMe(); that should return foo as it casts the object and then makes the call.
JB King