Абстрактное свойство с публичным геттером, определить частный сеттер в конкретном классе? - PullRequest
46 голосов
/ 10 января 2011

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

Что у меня так далеко:

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 не выдает ошибку, но даже несмотря на то, что метод доступа Value будет скомпилирован в set_Value, он не работает наоборот. Определение set_Value не означает, что Value получает установленный метод доступа. Поэтому я не могу присвоить значение свойству ConcreteClass3.Value. Я могу использовать ConcreteClass3.set_Value ("значение"), но это не то, чего я пытаюсь достичь здесь.

Возможно ли, чтобы абстрактный класс требовал общедоступного метода получения, в то же время позволяя определить необязательный метод установки в производном классе?

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

Ответы [ 3 ]

33 голосов
/ 10 января 2011

К сожалению, вы не можете делать именно то, что вы хотите. Вы можете сделать это с помощью интерфейсов:

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;
    }
}
6 голосов
/ 06 марта 2014

Нашел решение: Как переопределить свойство только для получения с помощью установщика в C #?

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в то же время возможность переопределения в сеттере.

0 голосов
/ 10 января 2011

Не очень элегантно, но это самое близкое, что вы можете получить, не делая ничего похожего на бетонclass3

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's 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(); } }
}
...