Want to show your appreciation? Please to my charity.

Friday, May 08, 2009

C#.Net Calling Grandparent's Virtual Method (base.base in C#)

Update: Open source project SharpCut delivers a less than 50K library which does what described here in one line plus much more. Check it out.

Calling parent's virtual method is easy, you can use base.VirtualMethod(). But C# has no support to call grandparent's virtual method. I guess everybody tried base.base.VirtualMethod() and that won't work.

I have searched the Google for how to call grandparents virtual method in C# learned that this isn't supported by VB.Net and C#. Only C++/CLI gives this power.

I need to do something very similar to the OnMouseDown example in this post. I can code in C++ but this is a class in a big C# project so this is no an option. The IL code in the C++ article reminded me that I should be able to use Reflection Emit to do the same.

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

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

    class C : B
        private static readonly DynamicMethod baseBaseFoo;
        static C()
            MethodInfo fooA = typeof(A).GetMethod("foo", BindingFlags.Public | BindingFlags.Instance);

            baseBaseFoo = new DynamicMethod(
                new Type[] { typeof(A) },
            ILGenerator il = baseBaseFoo.GetILGenerator();
            il.Emit(OpCodes.Ldarg, 0);
            il.EmitCall(OpCodes.Call, fooA, null);
        public override string foo() { return (string)baseBaseFoo.Invoke(null, new object[]{this}); }

It works, C.foo() returns "A". But this can obviously be improved in many ways. In next post, we'll try to

  • Create a utility method, or better extension method, that does all the IL generation.
  • Instead of _fooA.Invoke, we can probably use a delegate for type safety and performance.

So that we can write the code like this:

    class C : B
        private static readonly Func<A, string> baseBaseFoo = 
            typeof(A).GetNonVirtualInvoker<Func<A, string>>("foo");
        public override string foo() { return baseBaseFoo(this); }

Looks cool, isn't it?

1 comment:

Tomas Hood said...

No one commented on this? In all of these years since the posting? This is a workable workaround when you have a closed library. Thanks for this. Cheers.

Post a Comment