Подтвердить что ты не робот

Абстрактное свойство с открытым геттером, определить частный сеттер в конкретном классе?

Я пытаюсь создать абстрактный класс, который определяет свойство с геттером. Я хочу оставить это до производных классов, чтобы решить, хотят ли они реализовать сеттер для свойства или нет. Возможно ли это?

Что я до сих пор:

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, позволяя определить опциональный сеттер в производном классе?

Если вам интересно, это всего лишь теоретический вопрос. У меня нет реальной ситуации, когда требуется нечто подобное. Но я могу представить абстрактный класс, который не заботится о том, как свойство устанавливается, но это должно быть в состоянии получить свойство.

4b9b3361

Ответ 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(); } }
}