0

I have a simple class hierarchy where I have a virtual method that is overriden. But at certain callsites I want to call the base class version of this method rather than the virtual method.

For example:

public class A {
    public virtual void Foo() {...}
}

public class B : A {
    public override void Foo() {...}
}

public class Program {
    public void SomeMethod()
    {
       ...

       //  ListofA is type IEnumerable<A>
       foreach (var item in ListofA)
       {
           // I want this to call A.Foo(), rather than B.Foo()
           // But everything I've tried, which has really just been casting, has resulted in B.Foo()
           item.Foo();
       }
    }
}
Kang Su
  • 701
  • 2
  • 10
  • 19
  • Please explain why you want to have that behavior. – Daniel Hilgarth Mar 10 '11 at 20:39
  • I think my answer to this might be somewhat vague, as its not my code. A colleague asked me about it -- the core issue being that the virtual method is always the right thing to do... except in this one new code path. It looked like something simple to do, but then realized I didn't know how to do it in C#. But thought there must be a way. The details of what the code is actually doing, I don't know very well, and would probably give you more wrong info than correct if I tried to recall. Note, he did end up just refactoring the code altogether. – Kang Su Mar 10 '11 at 21:00
  • You are right, your answer is vague ;-) But refactoring is the way I would have suggested. – Daniel Hilgarth Mar 10 '11 at 21:03

8 Answers8

8

You can't on an override. Overrides replace the original (from the standpoint of the caller). An overridden method may call the base, but you can't externally.

James Michael Hare
  • 37,767
  • 9
  • 73
  • 83
  • Thanks, that's what I was afraid of. – Kang Su Mar 10 '11 at 20:49
  • @Kang: You shouldn't be afraid of it! The whole point with VIRTUAL methods is that they are VIRTUAL. :) But if you explain the context and why you think a problem would be solved if you could invoke a specific implementation, someone may know a way to achieve your target. – The Dag Mar 10 '11 at 20:53
3

@James is right. To build on his answer, since you can call the base version from the overridden one, you could send some kind of a flag into the method to tell it whether to execute its own implementation or the overridden one. Something like this:

public override void Foo(bool useBaseImplementation)
{
    if(useBaseImplementation)
    {
        base.Foo(useBaseImplementation);
    }
    else
    {
        //other stuff here
    }
}

In order for it to work, you'd have to have the flag as a parameter for the base one as well, but you could just ignore it there. Not elegant, maybe downright ugly, but does what you're looking for.

Zann Anderson
  • 4,767
  • 9
  • 35
  • 56
  • Doing so would negate the whole point of using virtual methods in the first place. If it's his code - or rather, code he can change - why not just abandon the whole virtual thing to start with? And if it's not the same operation, why not introduce a new method in B rather than pretend it's another implementation of Foo()? – The Dag Mar 10 '11 at 20:56
  • 1
    I can't argue with that. The problem-solver in me jumped on this and said, "Aha! Here's a way to do this!" I did say it was "Not elegant, maybe downright ugly"...right? – Zann Anderson Mar 10 '11 at 21:00
1

If this is the case then what you want isn't actually an override; you should rethink your design. If instead of override you use new in the redefinition the method won't be polymorphic, but again, this is highly indicative of a flawed design. You would also need foreach (A item in ListofA)

Mark Sowul
  • 10,244
  • 1
  • 45
  • 51
1

I don't like my solution, beacause it sorta uglifies abstration, but maybe you could do the following:

public class A {
  public virtual void Foo() {...}
}

public class B : A {
  public override void Foo() {...}
  public override void parentFoo(){
    base.Foo();
  }
}

public class Program {
  public void SomeMethod(){
    ...

     //  ListofA is type IEnumerable<A>
     foreach (var item in ListofA){
       item.Foo(); //calls B.Foo()
       item.parentFoo(); //calls B.parentFoo() == A.Foo()
     }
  }
}
Martijn
  • 11,964
  • 12
  • 50
  • 96
  • That was the first solution I came up with. Thought it was too ugly as well. :-) – Kang Su Mar 10 '11 at 20:50
  • IMO, the fact that that would want to unhide an overriden method would be code smell. Without more info I don't know something is wrong yet, but, it sure smells fishy. – Martijn Mar 10 '11 at 20:52
  • I agree. So let us agree it's not a solution. Can the OP please let us know *why* he wants to do this? – The Dag Mar 10 '11 at 21:02
0

If var item = new A(), it will call A.Foo().

Kumar
  • 997
  • 5
  • 8
0

You can call base implementation using the base keyword INSIDE the class, but if You are trying to call it from the other class I am pretty sure You are violating a Liskov Substitution Principle in Your code, as Any subclass shoudl provide such an implementation to virutal methods to be completely substitutable for superclass. Revisit YOUR design.

luckyluke
  • 1,553
  • 9
  • 16
0

You can achieve that with using new rather than override. It is very well explained here: http://msdn.microsoft.com/en-us/library/ms173153%28v=vs.80%29.aspx

treze
  • 3,159
  • 20
  • 21
  • 1
    What's the point hiding a method in order to call the method you are hiding? If there is no need for Foo() invoked on an instance of B to ever do anything but A.Foo(), just don't override it. – The Dag Mar 10 '11 at 21:04
  • I didn't say it makes any sense. You can just realize the behavior he asked for this way. If you call it on a type B then B.Foo() is invoked, if you call it on a type A then A.Foo() (the base implementation) is invoked. – treze Mar 11 '11 at 15:07
0

One possible workaround is not to make the method virtual, but replace it using the new keyword:

   class Program
{
    static void Main(string[] args)
    {
        List<A> list = new List<A>
        {
            new B(),
            new B(),
            new B(),
            new B()
        };

        foreach (A a in list)
        {
            a.Foo();
        }

        foreach (B b in list)
        {
            b.Foo();
        }

        Console.ReadLine();
    }
}

public class A
{
    public void Foo()
    {
        Console.WriteLine("Base");
    }
}

public class B : A
{
    public new void Foo()
    {
        Console.WriteLine("Derived");
    }
}

This will only call the B.Foo() implementation if the reference you use is of type B. I wouldn't encourage you to do this, since I've never came accross a situation where the new keyword made sense.

J. Tihon
  • 4,439
  • 24
  • 19
  • That's incorrect. They type of the reference does not matter. The (runtime) type of the referenced object matters - as your example proves. – The Dag Mar 10 '11 at 20:57