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(
                "foo_A",
                typeof(string),
                new Type[] { typeof(A) },
                typeof(A));
            ILGenerator il = baseBaseFoo.GetILGenerator();
            il.Emit(OpCodes.Ldarg, 0);
            il.EmitCall(OpCodes.Call, fooA, null);
            il.Emit(OpCodes.Ret);
        }
        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?

No comments:

Post a Comment