The following might be general knowledge I was just simply lacking, but eh. Some time ago, we had a bug case which included virtual properties. Abstracting the context a bit, consider the following code, and apply breakpoint to specified area :
class Program
{
static void Main(string[] args)
{
Derived d = new Derived();
d.Property = "AWESOME";
}
}
class Base
{
string _baseProp;
public virtual string Property
{
get
{
return "BASE_" + _baseProp;
}
set
{
_baseProp = value;
//do work with the base property which might
//not be exposed to derived types
//here
Console.Out.WriteLine("_baseProp is BASE_" + value.ToString());
}
}
}
class Derived : Base
{
string _prop;
public override string Property
{
get { return _prop; }
set
{
_prop = value;
base.Property = value;
} //<- put a breakpoint here then mouse over BaseProperty,
// and then mouse over the base.Property call inside it.
}
public string BaseProperty { get { return base.Property; } private set { } }
}
While in the Derived
object context, you can get the same behavior when adding base.Property
as a watch, or typing base.Property
into the quickwatch.
Took me some time to realize what was going on. In the end I was enlightened by the Quickwatch. When going into the Quickwatch and exploring the Derived
object d (or from the object's context, this
) and selecting the field base
, the edit field on top of the Quickwatch displays the following cast:
((TestProject1.Base)(d))
Which means that if base is replaced as such, the call would be
public string BaseProperty { get { return ((TestProject1.Base)(d)).Property; } private set { } }
for the Watches, Quickwatch and the debugging mouse-over tooltips, and it would then make sense for it to display "AWESOME"
instead of "BASE_AWESOME"
when considering polymorphism. I'm still unsure why it would transform it into a cast, one hypothesis is that call
might not be available from those modules' context, and only callvirt
.
Anyhow, that obviously doesn't alter anything in terms of functionality, Derived.BaseProperty
will still really return "BASE_AWESOME"
, and thus this was not the root of our bug at work, simply a confusing component. I did however find it interesting how it could mislead developpers which would be unaware of that fact during their debug sessions, specially if Base
is not exposed in your project but rather referenced as a 3rd party DLL, resulting in Devs just saying :
"Oi, wait..what ? omg that DLL is
like, ..doing something funny"