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.
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
.
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 - Marc Gravell♦
Inside of ChildClass.methodTwo()
, you can call base.methodTwo()
.
Outside of the class, calling ((ParentClass)a).methodTwo())
will call ChildClass.methodTwo
. That's the entire reason why virtual methods exist.
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!
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();
}
}
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.
To my knowledge, once a method has been overridden then you can't call the parent method.
I would think that it is not possible unless you make instance of the ParentClass directly. Thats the very essense of inheritance, polymorphism...
I stumbled upon this looking for help and ended up with my own approach to calling ancestor versions of a method. This is more of a work-around which assumes you can edit the ancestor class:
Put the functionality in question in the ancestor class into a static method, with the necessary parameters. The method in that class can call it so it need not duplicate the functionality, and the child class can call to that functionality if desired via the static method. That way, it can be done even within a method and can cite which specific class it wants to invoke. Also, it can access farther back ancestors than mere parents, which is the limitation of use "base".