Следующее может быть общим знанием, которого мне просто не хватало, но да. Некоторое время назад у нас был случай ошибки, который включал виртуальные свойства. Немного абстрагируя контекст, рассмотрите следующий код и примените точку останова к указанной области:
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 { } }
}
Находясь в Derivedконтексте объекта, вы можете получить то же поведение при добавлении base.Propertyв качестве часов или набравbase.Property в быстрые часы.
Мне потребовалось некоторое время, чтобы понять, что происходит. В конце концов я был просветлен Quickwatch. Когда вы входите в Quickwatch и исследуете Derivedобъект d (или из контекста объекта this) и выбираете поле base, поле редактирования в верхней части Quickwatch отображает следующее приведение:
((TestProject1.Base)(d))
Это означает, что если база будет заменена как таковая, вызов будет
public string BaseProperty { get { return ((TestProject1.Base)(d)).Property; } private set { } }
для часов, Quickwatch и отладочных подсказок при наведении курсора, и тогда имело бы смысл отображать их "AWESOME"вместо "BASE_AWESOME"рассмотрения полиморфизма. Я до сих пор не уверен, почему это превратило бы его в приведение, одна гипотеза которого callможет быть недоступна из контекста этих модулей, и толькоcallvirt .
В любом случае, это, очевидно, ничего не меняет с точки зрения функциональности, Derived.BasePropertyвсе равно действительно вернется "BASE_AWESOME", и, таким образом, это не было корнем нашей ошибки на работе, просто запутывающим компонентом. Однако мне было интересно, как это могло бы ввести в заблуждение разработчиков, которые не будут знать об этом во время их отладочных сессий, особенно если они Baseне представлены в вашем проекте, а скорее упоминаются как сторонние DLL, в результате чего разработчики просто говорят:
«Ой, подождите .. что? О боже, что это DLL, что-то смешное»