Це можливо
tl; dr - Якщо ви хочете, ви можете замінити метод отримання лише за допомогою сеттера. Це в основному просто:
Створіть new
властивість, яка має і а, get
і set
вживання, використовуючи те саме ім'я.
Якщо ви нічого не робите, то старий get
метод все одно буде називатися, коли похідний клас буде викликаний через його базовий тип. Щоб виправити це, додайтеabstract
проміжний шар, який використовує override
старий get
метод, щоб змусити його повернути результат нового get
методу.
Це дає нам змогу переосмислити властивості за допомогою get
/ set
навіть, якщо їх у базовому визначенні не вистачало.
Як бонус, ви також можете змінити тип повернення, якщо хочете.
Якщо базовим було визначення get
-лише, тоді можна використовувати більш похідний тип повернення.
Якщо базовим було визначення set
-лише, тоді ви можете отримати менш похідний тип повернення.
Якщо базове визначення вже було get
/set
, то:
ви можете використовувати більш похідний тип повернення, якщо ви робите це set
-лише;
ви можете використовувати менш похідний тип повернення, якщо ви робите це get
- тільки.
У всіх випадках ви можете зберігати той самий тип повернення, якщо хочете. Наведені нижче приклади використовують той же тип повернення для простоти.
Ситуація: Попередня get
власність
У вас є структура класу, яку ви не можете змінити. Можливо, це лише один клас, або це вже існуюче дерево спадкування. У будь-якому випадку ви хочете додати set
метод до властивості, але не можете.
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; } }
}
Проблема: Неможливо- override
тільки get
зget
/set
Ви хочете мати override
з get
/ set
властивістю, але він не буде компілюватися.
public class C : B
{
private int _x;
public override int X
{
get { return _x; }
set { _x = value; } // Won't compile
}
}
Рішення: Використовуйте abstract
проміжний шар
Хоча ви не можете безпосередньо override
з власністю get
/ set
, ви можете :
Створіть new
get
/ set
з власним іменем /.
override
старий get
метод з аксесуаром до нового get
методу для забезпечення узгодженості.
Отже, спочатку ви пишете abstract
проміжний шар:
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; }
}
Потім ви пишете клас, який не збирався б раніше. Це буде компілювати на цей раз , тому що ви на самому ділі не override
«ІНГ в get
-Тільки власності; натомість ви замінюєте його за допомогою new
ключового слова.
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; } }
}
Результат: Все працює!
Очевидно, це працює як задумано 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.
Все ще працює за призначенням, якщо розглядати його D
як один із його базових класів, наприклад, A
або B
. Але причина, чому це працює, може бути трохи менш очевидною.
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.
Однак визначення базового класу get
досі остаточно переосмислене визначенням похідного класу get
, тому воно все ще повністю узгоджується.
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.
Обговорення
Цей метод дозволяє додавати set
методи до get
-тільки властивостей. Ви також можете використовувати його, щоб робити такі речі, як:
Змініть будь-яку властивість на властивість get
-only, set
-only або get
-and- set
, незалежно від того, що вона була в базовому класі.
Змініть тип повернення методу у похідних класах.
Основні недоліки полягають у тому, що abstract class
в дереві спадкування є більше кодування і додаткового . Це може трохи дратувати конструкторів, які приймають параметри, оскільки їх потрібно копіювати / вставляти в проміжний шар.