Quanto segue potrebbe essere una conoscenza generale che mi mancava semplicemente, ma eh. Qualche tempo fa, abbiamo avuto un bug case che includeva proprietà virtuali. Estrarre un po 'il contesto, considerare il codice seguente e applicare il punto di interruzione all'area specificata:
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 { } }
}
Mentre si è nel Derived
contesto dell'oggetto, è possibile ottenere lo stesso comportamento quando si aggiunge base.Property
come orologio o si digitabase.Property
nel quickwatch.
Mi ci è voluto un po 'di tempo per capire cosa stesse succedendo. Alla fine sono stato illuminato dal Quickwatch. Quando si accede a Quickwatch ed esplora l' Derived
oggetto d (o dal contesto dell'oggetto this
) e si seleziona il campo base
, il campo di modifica nella parte superiore di Quickwatch visualizza il seguente cast:
((TestProject1.Base)(d))
Ciò significa che se la base viene sostituita come tale, la chiamata sarebbe
public string BaseProperty { get { return ((TestProject1.Base)(d)).Property; } private set { } }
per gli orologi, Quickwatch e le descrizioni dei comandi del mouse per il debug, e avrebbe quindi senso che venga visualizzato "AWESOME"
invece di "BASE_AWESOME"
considerare il polimorfismo. Non sono ancora sicuro del perché lo trasformerebbe in un cast, un'ipotesi è che call
potrebbe non essere disponibile dal contesto di quei moduli, e solo callvirt
.
Ad ogni modo, ciò ovviamente non altera nulla in termini di funzionalità, Derived.BaseProperty
tornerà comunque davvero "BASE_AWESOME"
, e quindi questa non era la radice del nostro bug al lavoro, semplicemente un componente confuso. Tuttavia, ho trovato interessante il modo in cui potrebbe fuorviare gli sviluppatori che non sarebbero a conoscenza di questo fatto durante le loro sessioni di debug, specialmente se Base
non sono esposti nel progetto ma piuttosto indicati come una DLL di terze parti, risultando in Dev che dicono solo:
"Oi, aspetta ... cosa? Omg che DLL è come ... facendo qualcosa di divertente"