É possível
tl; dr - Você pode substituir um método get-only por um setter, se desejar. É basicamente apenas:
Crie uma new
propriedade que tenha a get
e a set
usando o mesmo nome.
Se você não fizer mais nada, o get
método antigo ainda será chamado quando a classe derivada for chamada por meio de seu tipo base. Para corrigir isso, adicione uma abstract
camada intermediária que use override
no get
método antigo para forçá-lo a retornar o get
resultado do novo método.
Isso nos permite substituir propriedades por get
/ set
mesmo que não possuam uma em sua definição básica.
Como bônus, você também pode alterar o tipo de retorno, se desejar.
Se a definição de base fosse get
apenas, você poderá usar um tipo de retorno mais derivado.
Se a definição base fosse set
apenas, você pode usar um tipo de retorno menos derivado.
Se a definição base já era get
/ set
, então:
Em todos os casos, você pode manter o mesmo tipo de retorno, se desejar. Os exemplos abaixo usam o mesmo tipo de retorno para simplificar.
Situação: get
propriedade unicamente pré-existente
Você tem alguma estrutura de classe que não pode modificar. Talvez seja apenas uma classe ou uma árvore de herança pré-existente. Seja qual for o caso, você deseja adicionar um set
método a uma propriedade, mas não pode.
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: Não é possível override
a get
-apenas com get
/set
Você deseja override
com um get
/ set
property, mas ele não será compilado.
public class C : B
{
private int _x;
public override int X
{
get { return _x; }
set { _x = value; } // Won't compile
}
}
Solução: use uma abstract
camada intermediária
Embora você não possa diretamente override
com um get
/ set
property, você pode :
Crie uma propriedade new
get
/ set
com o mesmo nome.
override
o get
método antigo com um acessador para o novo get
método para garantir consistência.
Então, primeiro você escreve a abstract
camada intermediária:
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; }
}
Em seguida, você escreve a classe que não seria compilada anteriormente. Desta vez, ele será compilado porque você não está realmente override
na get
propriedade -only; em vez disso, você está substituindo-o usando a new
palavra - chave.
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: Tudo funciona!
Obviamente, isso funciona como planejado 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.
Tudo ainda funciona como pretendido ao visualizar D
como uma de suas classes base, por exemplo, A
ou B
. Mas, a razão pela qual funciona pode ser um pouco menos óbvia.
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.
No entanto, a definição de classe base get
ainda é substituída pela definição de classe derivada de get
, portanto ainda é completamente consistente.
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.
Discussão
Este método permite adicionar set
métodos às get
propriedades -only. Você também pode usá-lo para fazer coisas como:
Altere qualquer propriedade para uma propriedade get
-only, set
-lyly ou get
-and- set
, independentemente do que estava em uma classe base.
Altere o tipo de retorno de um método nas classes derivadas.
As principais desvantagens são que há mais codificação a ser feita e um extra abstract class
na árvore de herança. Isso pode ser um pouco irritante para os construtores que aceitam parâmetros porque eles precisam ser copiados / colados na camada intermediária.