Public Service Announcement: You may have noticed that trying to evaluate members using C#'s 'base' keyword in the debugger still calls the derived members. (The 'base' keyword lets you access base class member implementations from within  a derived class, which is very useful when the members are polymorphic and so just calling the member directly would go through virtual dispatch and call the derived implementation).

Here's an example:


using System;

class Program
{
    static void Main(string[] args)
    {
        DerivedClass d = new DerivedClass();
        d.Test();
    }
}

class BaseClass
{
    public virtual string Thing()
    {
        return "base";
    }
}
class DerivedClass : BaseClass
{
    public override string Thing()
    {        
        return "derived";
    }

    public void Test()
    {
        // C#'s 'base' keyword lets us explicitly call the base class method instead
        // of using polymorphism to call the derived method.
        string b = base.Thing(); // This will be "base"
        
        // This will print "base, derived"
        Console.WriteLine("{0},{1}", b, this.Thing());

        // However, if we evaluate "base.Thing()" in the debugger's watch window, it will
        // still use polymorphism and incorrectly evaluate to "derived"

    }
}

 

So if you evaluate "base.Thing()" in the debugger's immediate / watch windows, it yields "derived" instead of "base".

Why?
The problem is actually in the underlying CLR debugging services. To evaluate "base.Thing()", the debugger needs to do a func-eval. However, ICD does all func-evals with virtual dispatch

On one hand, debugger authors really really don't want to be doing the virtual dispatch themselves. That would involve crawling all over the type / interface hierarchy trying to figure out which method to call. And most of the time, you want virtual dispatch, so that seemed an intelligent default. For example, this is the correct behavior for "this.Thing()", or inspecting any other variables. In fact, the only place I've see this  break in practice is when explicitly inspecting polymorphic members via the 'base' keyword.

FWIW, I think the ideal thing to do would be to have a switch on ICorDebugEval that lets you switch between virtual dispatch and non-virtual dispatch.

Whose bug is this?
Clearly, there's a bug to the end-user, but there's an interesting philosophical discussion here about which component is at fault. The CLR's or Visual Studios? And if in VS, which component? The language specific expression evaluator? The debug-engine?

So you could argue the bug could be:
1) ICorDebug should have had better documentation to clearly call out that func-eval is virtual dispatch (the latest version of the idl file does; but I haven't checked the other docs, such as earlier idl files)
2) ICorDebug really should have had the functionality to begin with because it should ensure that it provides the necessary features for the overall system to work. (I personally wouldn't call this a "bug" because although it's missing functionality, the functionality it does have is correct; perhaps a "design shortcoming")
3) The debugger (Visual Studio) should not even attempt to evaluate virtuals on the 'base' keyword because it can't be implemented properly. So VS should just fail an attempt to evaluate "base.Thing()".   For this case, you then have to decide which component within VS would be responsible.

FWIW, I think the ideal thing to do would be to have a switch on ICorDebugEval that lets you switch between virtual dispatch and non-virtual dispatch.