Es posible
tl; dr : puede anular un método get-only con un setter si lo desea. Básicamente es solo:
Cree una new
propiedad que tenga a get
y a set
usando el mismo nombre.
Si no hace nada más, get
se seguirá llamando al método anterior cuando se llame a la clase derivada a través de su tipo base. Para solucionar esto, agregue una abstract
capa intermedia que use override
en el get
método anterior para forzarlo a devolver el get
resultado del nuevo método.
Esto nos permite anular propiedades con get
/ set
incluso si carecían de una en su definición base.
Como beneficio adicional, también puede cambiar el tipo de devolución si lo desea.
Si la definición base era get
-solo, entonces puede usar un tipo de retorno más derivado.
Si la definición base era set
-solo, entonces puede usar un tipo de retorno menos derivado.
Si la definición base ya era get
/ set
, entonces:
En todos los casos, puede mantener el mismo tipo de retorno si lo desea. Los siguientes ejemplos usan el mismo tipo de retorno por simplicidad.
Situación: get
propiedad preexistente solo
Tiene alguna estructura de clase que no puede modificar. Tal vez es solo una clase, o es un árbol de herencia preexistente. En cualquier caso, desea agregar un set
método a una propiedad, pero no puede.
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: No puede override
el get
-sólo con get
/set
Desea override
con una propiedad get
/ set
, pero no se compilará.
public class C : B
{
private int _x;
public override int X
{
get { return _x; }
set { _x = value; } // Won't compile
}
}
Solución: use una abstract
capa intermedia
Si bien no puede directamente override
con una propiedad get
/ set
, puede :
Cree una propiedad new
get
/ set
con el mismo nombre.
override
El get
método anterior con un descriptor de acceso al nuevo get
método para garantizar la coherencia.
Entonces, primero escribes la abstract
capa intermedia:
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; }
}
Luego, escribe la clase que no se compilaría antes. Se va a compilar esta vez porque no estás en realidad override
'ing la get
propiedad -sólo; en cambio, lo está reemplazando con la new
palabra clave.
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; } }
}
Resultado: ¡Todo funciona!
Obviamente, esto funciona según lo 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.
Todo sigue funcionando según lo previsto cuando se ve D
como una de sus clases base, por ejemplo, A
o B
. Pero, la razón por la que funciona podría ser un poco menos obvio.
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.
Sin embargo, la definición de clase base de get
todavía está anulada en última instancia por la definición de la clase derivada de get
, por lo que sigue siendo completamente coherente.
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.
Discusión
Este método le permite agregar set
métodos a solo get
propiedades. También puedes usarlo para hacer cosas como:
Cambie cualquier propiedad a una propiedad get
-only, set
-only o get
-and- set
, independientemente de lo que haya sido en una clase base.
Cambiar el tipo de retorno de un método en clases derivadas.
Los principales inconvenientes son que hay más codificación que hacer y un extra abstract class
en el árbol de herencia. Esto puede ser un poco molesto con los constructores que toman parámetros porque deben copiarse / pegarse en la capa intermedia.