Saturday, August 18, 2007

Calling Virtual Method of a Class Base to Base Class

You will probably never really need to do this, but if it happens, here is how it can be accomplished.

So, assume you have two classes Base and Derived.  The Base class introduces a virtual method named Test.  The Derived class overrides this method.

Now, as I said in very rare circumstances, you may need to derive another class from the Derived class and in the overridden method Test call original version of Test method.  By original I mean implementation provided by the Base class.

C# and VB.Net, the most popular .Net languages do not provide any way to write something similar to:

class DerivedFromDerived : Derived
{
public override void Test()
{
base.base.Test();
}
}

When you call a base class version of Test() C# compiler generates:

.method public hidebysig virtual instance void Test() cil managed
{
.maxstack 8
L_0000:
nop
L_0001:
ldarg.0
L_0002:
call instance void Derived::Test()
L_0007:
nop
L_0008:
ret
}


The goal is to make compiler generate:


L_0002: call instance void Base::Test()


The syntax of method name used in IL reminded me that C++ always allowed invoking an implementation of the very base class.  And indeed, the straightforward solution is to implement it in C++/CLI:

    public ref class DerivedFromDerived: public Derived
{
public:
virtual void Test()
override
{
Base::Test();
}
};

This C++ code generates verifiable safe IL code. 

7 comments:

Anonymous said...

Any chance for porting/using this in C#? Examples would be appreciated.

Yuriy Solodkyy said...

Unfortunatelly, i have no solution for this in C#.

Anonymous said...

from http://www.rsdn.ru/forum/?mid=475911

using System;
using System.Reflection;

namespace ConsoleApplication1 {

class Class1 {

[STAThread]
static void Main(string[] args) {
new C().Test();
Console.ReadLine();
}
}

public delegate void MD();

class A {
protected virtual void M() {
Console.WriteLine("A.M");
}
}

class B:A {
protected override void M() {
Console.WriteLine("B.M");
}
}

class C:B {
protected override void M() {
Console.WriteLine("C.M");
}
public void Test() {
A a = new A();
MD am = (MD)Delegate.CreateDelegate(typeof(MD), a, "M");
am.GetType().BaseType.BaseType.GetField("_target", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(am, this);
am(); }

}
}

Yuriy Solodkyy said...

I havn't tried, but I am sure that this requires full trust. C++ sample woks in partial trust environment.

Iassen Assenov said...

In VB.Net you can implement a 'helper' method in the base class and call it from DerivedFromDerived. It will look something like:

Class CBase
...
Public Sub HelperTest(...)
MyClass.Test(...)
End Sub

End Class

And then do: objDerFromDer.HelperTest()

This capability is not available in C# :(

Anonymous said...

Really nice article ...thanks buddy..wat is the magic behind this, could you explain me..

My Name : senthilkumar
Email :senthil.mailto@gmail.com

Bill said...

It is not pretty but using explicit interface implementation in C# is doable.

using System;

namespace derivedevent
{
internal interface Blah
{
void Test ();
}

class Program : Blah
{
static void Main (string[] args)
{
new Program3 ().Test ();
}

public virtual void Test ()
{
((Blah)this).Test ();
}

void Blah.Test ()
{
Console.WriteLine ("Program");
}
}

class Program2 : Program
{
public override void Test ()
{
base.Test ();
Console.WriteLine ("Program2");
}
}

class Program3: Program2
{
public override void Test ()
{
((Blah)this).Test ();
Console.WriteLine ("Program3");
}
}

}