Це можливо
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в дереві спадкування є більше кодування і додаткового . Це може трохи дратувати конструкторів, які приймають параметри, оскільки їх потрібно копіювати / вставляти в проміжний шар.