È possibile
tl; dr - Se lo desideri, puoi sovrascrivere un metodo get-only con un setter. Fondamentalmente è solo:
Creare una new
proprietà con sia a get
che a set
usando lo stesso nome.
Se non fai altro, il vecchio get
metodo verrà comunque chiamato quando la classe derivata viene chiamata attraverso il suo tipo base. Per risolvere questo problema, aggiungi un abstract
livello intermedio che utilizza override
il vecchio get
metodo per forzarlo a restituire il get
risultato del nuovo metodo.
Questo ci consente di sovrascrivere le proprietà con get
/ set
anche se ne mancava una nella loro definizione di base.
Come bonus, puoi anche cambiare il tipo di ritorno, se lo desideri.
Se la definizione di base era get
-solo, è possibile utilizzare un tipo restituito più derivato.
Se la definizione di base era set
-solo, puoi usarci un tipo di ritorno meno derivato.
Se la definizione di base era già get
/ set
, quindi:
In tutti i casi, è possibile mantenere lo stesso tipo di restituzione, se lo si desidera. Gli esempi seguenti utilizzano lo stesso tipo restituito per semplicità.
Situazione: get
proprietà solo esistente
Hai una struttura di classe che non puoi modificare. Forse è solo una classe o è un albero ereditario preesistente. In ogni caso, si desidera aggiungere un set
metodo a una proprietà, ma non è possibile.
public abstract class A // Pre-existing class; can't modify
{
public abstract int X { get; } // You want a setter, but can't add it.
}
public class B : A // Pre-existing class; can't modify
{
public override int X { get { return 0; } }
}
Problema: Impossibile override
il get
-Solo con get
/set
Si desidera override
con una proprietà get
/ set
, ma non verrà compilata.
public class C : B
{
private int _x;
public override int X
{
get { return _x; }
set { _x = value; } // Won't compile
}
}
Soluzione: utilizzare uno abstract
strato intermedio
Anche se non puoi direttamente override
con una proprietà get
/ set
, puoi :
Crea una proprietà new
get
/ set
con lo stesso nome.
override
il vecchio get
metodo con un accessor al nuovo get
metodo per garantire coerenza.
Quindi, prima scrivi il abstract
livello intermedio:
public abstract class C : B
{
// Seal off the old getter. From now on, its only job
// is to alias the new getter in the base classes.
public sealed override int X { get { return this.XGetter; } }
protected abstract int XGetter { get; }
}
Quindi scrivi la classe che non si sarebbe compilata prima. Sarà compilazione questa volta perché si sta in realtà non override
'ing l' get
immobile -Solo; invece, lo stai sostituendo usando la new
parola chiave.
public class D : C
{
private int _x;
public new virtual int X { get { return this._x; } set { this._x = value; } }
// Ensure base classes (A,B,C) use the new get method.
protected sealed override int XGetter { get { return this.X; } }
}
Risultato: tutto funziona!
Ovviamente, questo funziona come previsto D
.
var test = new D();
Print(test.X); // Prints "0", the default value of an int.
test.X = 7;
Print(test.X); // Prints "7", as intended.
Tutto funziona come previsto quando viene visualizzato D
come una delle sue classi di base, ad esempio A
o B
. Ma il motivo per cui funziona potrebbe essere un po 'meno ovvio.
var test = new D() as B;
//test.X = 7; // This won't compile, because test looks like a B,
// and B still doesn't provide a visible setter.
Tuttavia, la definizione della classe base di get
è ancora alla fine sostituita dalla definizione della classe derivata di get
, quindi è ancora completamente coerente.
var test = new D();
Print(test.X); // Prints "0", the default value of an int.
var baseTest = test as A;
Print(test.X); // Prints "7", as intended.
Discussione
Questo metodo consente di aggiungere set
metodi alle get
sole proprietà. Puoi anche usarlo per fare cose come:
Cambia qualsiasi proprietà in una get
-only, set
-only o get
-and- set
proprietà, indipendentemente da ciò che era in una classe base.
Modifica il tipo restituito di un metodo nelle classi derivate.
Gli svantaggi principali sono che c'è più codice da fare e un extra abstract class
nella struttura ereditaria. Questo può essere un po 'fastidioso con i costruttori che accettano parametri perché devono essere copiati / incollati nel livello intermedio.