Jaa


Non-virtual calls to virtual methods

C# compiler is known to emit virtual calls for non-virtual methods (callvirt instead of call IL instruction, maybe that be the topic of my next post). However, sometimes it's forced to do the exact opposite

Consider the following code

     class B
    {
        public virtual void Foo()
        {
            Console.WriteLine("Base::Foo");
        }
    }

    class D : B
    {
        public override void Foo()
        {
            base.Foo();
            this.Foo(); // this is infinite recursion. Put just for example
            Console.WriteLine("Derived::Foo");
        }
    }

Here B::Foo is a virtual method and hence should be called virtually for both the calls in D::Foo. However, that's not the case.

For the above code the emitted IL looks like

     L_0001: ldarg.0 
    L_0002: call instance void BaseCall.B::Foo()
    L_0007: nop 
    L_0008: ldarg.0 
    L_0009: callvirt instance void BaseCall.B::Foo()

So for base.Foo() call the non-virtual call instruction is generated and for the this.Foo() call the virtual callvirt instruction is generated.

The reason is obviously simple. If a virtual call was made on base.Foo() then the call would've landed in the derived D::Foo which would again call base.Foo() resulting in infinite recursion.

Any guess on what happens for the following code

     class B
    {
        public virtual void Foo()
        {
            Console.WriteLine("Base::Foo");
        }
    }

    class C : B
    {
        public override void Foo()
        {
            Console.WriteLine("C::Foo");
        }
    }

    class D : C
    {
        public override void Foo()
        {
            base.Foo(); 
            Console.WriteLine("Derived::Foo");
        }
    }

Comments

  • Anonymous
    September 26, 2007
    PingBack from http://www.artofbam.com/wordpress/?p=3300

  • Anonymous
    September 30, 2007
    The comment has been removed

  • Anonymous
    July 02, 2008
    Sometime back I had posted about a case where non-virtual calls are used for virtual methods and promised