Абстрактное свойство с открытым геттером, определить частный сеттер в конкретном классе?
Я пытаюсь создать абстрактный класс, который определяет свойство с геттером. Я хочу оставить это до производных классов, чтобы решить, хотят ли они реализовать сеттер для свойства или нет. Возможно ли это?
Что я до сих пор:
public abstract class AbstractClass {
public abstract string Value { get; }
public void DoSomething() {
Console.WriteLine(Value);
}
}
public class ConcreteClass1 : AbstractClass {
public override string Value { get; set; }
}
public class ConcreteClass2 : AbstractClass {
private string _value;
public override string Value {
get { return _value; }
}
public string Value {
set { _value = value; }
}
}
public class ConcreteClass3 : AbstractClass {
private string _value;
public override string Value {
get { return _value; }
}
public void set_Value(string value) {
_value = value;
}
}
В ConcreteClass1
, я получаю сообщение об ошибке на set
. Он не может переопределить set_Value
, потому что в AbstractClass не существует переопределяемого набора элементов доступа.
В ConcreteClass2
, я получаю сообщение об ошибке для Value
, потому что член с тем же именем уже объявлен.
ConcreteClass3
не дает ошибки, но даже несмотря на то, что атрибут набора значений будет скомпилирован в set_Value, он не работает наоборот. Определение set_Value
не означает, что Value
получает набор доступа. Поэтому я не могу присвоить значение свойству ConcreteClass3.Value. Я могу использовать ConcreteClass3.set_Value ( "значение" ), но это не то, что я пытаюсь достичь здесь.
Возможно ли, чтобы абстрактный класс требовал публичного getter, позволяя определить опциональный сеттер в производном классе?
Если вам интересно, это всего лишь теоретический вопрос. У меня нет реальной ситуации, когда требуется нечто подобное. Но я могу представить абстрактный класс, который не заботится о том, как свойство устанавливается, но это должно быть в состоянии получить свойство.
Ответы
Ответ 1
К сожалению, вы не можете делать именно то, что хотите. Вы можете сделать это с помощью интерфейсов, хотя:
public interface IInterface {
string MyProperty { get; }
}
public class Class : IInterface {
public string MyProperty { get; set; }
}
Как я бы это сделал, это иметь отдельный метод SetProperty в конкретных классах:
public abstract class AbstractClass {
public abstract string Value { get; }
}
public class ConcreteClass : AbstractClass {
private string m_Value;
public override string Value {
get { return m_Value; }
}
public void SetValue(string value) {
m_Value = value;
}
}
Ответ 2
Обнаружено решение: Как переопределить свойство только для getter с установщиком в С#?
public abstract class A
{
public abstract int X { get; }
}
public class B : A
{
public override int X { get { return 0; } }
}
/*public class C : B //won't compile: can't override with setter
{
private int _x;
public override int X { get { return _x; } set { _x = value; } }
}*/
public abstract class C : B //abstract intermediate layer
{
public sealed override int X { get { return this.XGetter; } }
protected abstract int XGetter { get; }
}
public class D : C //does same thing, but will compile
{
private int _x;
protected sealed override int XGetter { get { return this.X; } }
public new virtual int X { get { return this._x; } set { this._x = value; } }
}
D
теперь эквивалентен классу, наследуемому от B
, а также может переопределять в сеттере.
Ответ 3
Не очень элегантно, но это самое близкое, что вы можете получить, не делая что-то вроде того, что у вас есть в concreteclass3
public class Concrete : AbstractClass
{
public new void DoSomething()
{
Console.WriteLine(Value);
}
}
public abstract class AbstractClass
{
protected AbstractClass()
{
try
{
var value = Value;
}
catch (NotImplementedException)
{
throw new Exception("Value getter must be overriden in base class");
}
}
public void DoSomething()
{
Console.WriteLine(Value);
}
/// <summary>
/// Must be override in subclass
/// </summary>
public string Value { get { throw new NotImplementedException(); } }
}