Is there any way to call the parent version of an overridden method? (C# .NET)

56,074

Solution 1

At the IL level, you could probably issue a call rather than a callvirt, and get the job done - but if we limit ourselves to C# ;-p (edit darn! the runtime stops you: VerificationException: "Operation could destabilize the runtime."; remove the virtual and it works fine; too clever by half...)

Inside the ChildClass type, you can use base.methodTwo() - however, this is not possible externally. Nor can you go down more than one level - there is no base.base.Foo() support.

However, if you disable polymorphism using method-hiding, you can get the answer you want, but for bad reasons:

class ChildClass : ParentClass
{
    new public int methodTwo() // bad, do not do
    {
        return 2;
    }
}

Now you can get a different answer from the same object depending on whether the variable is defined as a ChildClass or a ParentClass.

Solution 2

Inside of ChildClass.methodTwo(), you can call base.methodTwo().

Outside of the class, calling ((ParentClass)a).methodTwo() will call ChildClass.methodTwo. That's the whole reason why virtual methods exist.

Solution 3

As mentioned above, something is bad with your class design if you need to call "base.base" in PRODUCTION code. But it is quite legitimate to use this technique if you are debugging or searching some workarrounds while using external libraries you cannot compile. It is unpleasant that C# does not provide this option directly. Still you may use Kenneth Xu solution with IL generator and Emit. It works.

class A { public virtual string foo() { return "A"; } }

class B : A { public override string foo() { return "B"; } }

// now in class C
class C : B {}      
// we can call virtual method "foo" from A using following code
MethodInfo fooA = typeof(A).GetMethod("foo", BindingFlags.Public | BindingFlags.Instance);

DynamicMethod baseBaseFoo = new DynamicMethod(
            "foo_A",
            typeof(string),
            new[] { typeof(A) },
            typeof(A));
        ILGenerator il = baseBaseFoo.GetILGenerator();
        il.Emit(OpCodes.Ldarg, 0);
        il.EmitCall(OpCodes.Call, fooA, null);
        il.Emit(OpCodes.Ret);

// call foo() from class A, it returns "A"
(string)baseBaseFoo.Invoke(null, new object[] { this });

For reference and a complete sample see http://kennethxu.blogspot.cz/2009/05/cnet-calling-grandparent-virtual-method.html

Thank you Kenneth Xu!

Solution 4

public class Parent 
{
    public string Method()
    {
       return "parent";

    }
}

public class Child:Parent
{
    public string Method()
    {
       return "child";

    }
}

Above code successfully overrides parent method yet value of parent method still unchanged.

You can return values from the Both Parent class and Child class using code below -

Child child = new Child();
string result = (((Parent)child).Method()) + child.Method();

But Visual Studio will show you a warning in Compile Time.

Solution 5

As Mark Gravell said, no, not externally. But here's another hack I have used. ChildClass can expose methodTwo() from the ParentClass for its own use or for external use. In your case:

class ChildClass : ParentClass {
    override public int methodTwo() {
        return 2;
    }
    public int ParentClass_methodTwo() {
        return base.methodTwo();
    }
}

// Now instead of
Console.WriteLine("ParentClass methodTwo: " + ((ParentClass)a).methodTwo());
// use
Console.WriteLine("ParentClass methodTwo: " + a.ParentClass_methodTwo());

In my case, the child class introduced the concept of a Peer, and I needed its override of methodTwo() to invoke the base version on the peer. By overridding it, however, it hid it... Or did it? This technique came to the rescue.

class ChildClass : ParentClass {
    ChildClass peer;
    override public int methodTwo() {
        return peer.ParentClass_methodTwo();
    }
    private int ParentClass_methodTwo() {
        return base.methodTwo();
    }
}
Share:
56,074

Related videos on Youtube

Jader Dias
Author by

Jader Dias

Perl, Javascript, C#, Go, Matlab and Python Developer

Updated on July 09, 2022

Comments

  • Jader Dias
    Jader Dias almost 2 years

    In the code below I tried in two ways to access the parent version of methodTwo, but the result was always 2. Is there any way to get the 1 result from a ChildClass instance without modifying these two classes?

    class ParentClass
    {
        public int methodOne()
        {
            return methodTwo();
        }
    
        virtual public int methodTwo()
        {
            return 1;
        }
    }
    
    class ChildClass : ParentClass
    {
        override public int methodTwo()
        {
            return 2;
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var a = new ChildClass();
            Console.WriteLine("a.methodOne(): " + a.methodOne());
            Console.WriteLine("a.methodTwo(): " + a.methodTwo());
            Console.WriteLine("((ParentClass)a).methodTwo(): "
             + ((ParentClass)a).methodTwo());
            Console.ReadLine();
        }
    }
    

    Update ChrisW posted this:

    From outside the class, I don't know any easy way; but, perhaps, I don't know what happens if you try reflection: use the Type.GetMethod method to find the MethodInfo associated with the method in the ParentClass, and then call MethodInfo.Invoke

    That answer was deleted. I'm wondering if that hack could work, just for curiosity.

  • Andrew Hare
    Andrew Hare over 15 years
    This is not a bad answer - I think he meant you can't call the overriden parent method from an instance of the child, which was the spirit of the question.
  • Michael Meadows
    Michael Meadows over 15 years
    .., and -1 for all the ways it gets overused/misused.
  • Andrew Hare
    Andrew Hare over 15 years
    Michael - you downvoted someones explanation of polymorphic behavior? Craig was simply explaining why things work the way that they do, don't flail about downvoting good answers simply because they explain a concept you happen to believe is overused.
  • Kevin Gauthier
    Kevin Gauthier over 15 years
    I'm guessing he was joking. :)
  • Michael Meadows
    Michael Meadows over 15 years
    didn't downvote. just wanted to throw in my -1 cent on the overuse of polymorphism. Sorry if that wasn't clear.
  • Jan Doggen
    Jan Doggen almost 9 years
    Please edit your answer and include the essentials. Your answer is in another castle.
  • Ananda G
    Ananda G about 8 years
    Do you have a references, It would be better if u do.
  • Peter Huber
    Peter Huber almost 7 years
    Why is using "new" bad in this case ? Is there any case where using "new" is good ?
  • Marc Gravell
    Marc Gravell almost 7 years
    @PeterHuber because it breaks polymorphism; the main use-case for new in this scenario is for making a type more specialized. For example, DbCommand has a public DbParameterCollection Parameters {get;} - but SqlCommand : DbCommand has a public new SqlParameterCollection Parameters {get;}. Both APIs return the same instance (achieved by a separate protected abstract property, namely DbParameterCollection - so the value will always be a SqlParameterCollection) - but the more-specific type exposes it in a more-specific way
  • Peter Huber
    Peter Huber almost 7 years
    @MarcGravell: Thanks for the information, although I don't really understand it in detail. For example I don't know if properties can be virtual and overridden. Methods are easier to understand. I came to this question, because my base class needed to call another virtual method in the base and not the overridden one. I got a stackoverflow, because the base class called the overriden version, which called the base class again. By changing override to new everything works fine now. I wish there would be a way to specify that the base virtual method needs to be called, but it seems impossible.
  • kofifus
    kofifus over 5 years
    can be done without the GetMethod reflection overhead ?
  • Guillermo Prandi
    Guillermo Prandi almost 4 years
    Your code does not use actual inheritance (override of virtual methods). It just creates a new function with the same name, which is not what was asked.