Переопределить Get, Но Не Установить


у меня есть абстрактный класс, который определяет get, а не set, потому что что касается этого абстрактного класса, ему нужно только get.

public abstract BaseClass
{
  public abstract double MyPop
  {get;}
}

однако в некоторых производных классах мне нужен set собственность, поэтому я смотрю на эту реализацию

public class DClass: BaseClass
{
  public override double MyPop
  {get;set;}
}

проблема в том, что я получил ошибку компиляции, сказав, что

*.набор: невозможно переопределить, потому что *. не имеет переопределяемого набора средство доступа.

хотя я думаю, что приведенный выше синтаксис совершенно законен.

есть идеи по этому поводу? Обходной путь, или почему это так?

Edit: единственный подход, который я могу придумать, - это поставить оба get и set как в абстрактном классе, и пусть подкласс бросает NotImplementedException если set называется и это не нужно. Это то, что мне не нравится, наряду со специальным методом сеттера .

13 68
c#

13 ответов:

новое в C# 6.0:

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

void Main()
{
    BaseClass demo = new DClass(3.6);
}

public abstract class BaseClass
{
    public abstract double MyPop{ get; }
}

public class DClass : BaseClass
{
    public override double MyPop { get; }
    public DClass(double myPop) { MyPop = myPop;}
}

одним из возможных ответов было бы переопределить геттер, а затем реализовать отдельный метод сеттера. Если вы не хотите, чтобы задатчик свойств был определен в базе, у вас не так много других вариантов.

public override double MyPop
{
    get { return _myPop; }
}

public void SetMyPop(double value)
{
    _myPop = value;
}

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

единственный случай, когда я знаю, где геттер определен и геттер / сеттер реализованы с помощью интерфейса:

public interface IBaseInterface
{
    double MyPop { get; }
}

public class DClass : IBaseInterface
{
    public double MyPop { get; set; }
}

Если BaseClass находится в вашей собственной кодовой базе, то вы можете сделать:

abstract public class BaseClass
{
    abstract public double MyPop { get; protected set; }
}

public class DClass : BaseClass
{
    private double _myProp;
    public override double MyProp
    {
        get { return _myProp; }
        protected set { _myProp = value; }
    }
}

EDIT: затем вы можете сделать общедоступный метод в DClass SetMyProp(double myProp) или тому подобное. Дизайн класса для вашей модели домена должен быть ясен или говорить сам за себя, почему вы не можете установить свойство непосредственно в базовом классе и почему вы можете сделать это в производном.

вы уверены, что делать то, что вы пытаетесь сделать было бы хорошим дизайном, если бы вы нашли способ сделать это?

Это позволит объектам подкласса вносить изменения в состояние, которые не могут сделать объекты родительского класса. Разве это не нарушает принцип замены Лискова?

вы могли бы сделать что-то вроде этого:

abstract class TestBase { public abstract int Int { get; } }

class TestDerivedHelper : TestBase
{
    private int _Int;
    public override int Int
    {
        get
        {
            return _Int;
        }
    }

    protected void SetInt(int value)
    {
        this._Int = value;
    }
}

class TestDerived : TestDerivedHelper
{
    public new int Int
    {
        get { return base.Int; }
        set { base.SetInt(value); }
    }
}

С помощью TestDerived будет иметь функциональность, которую вы ищете. Единственный недостаток, который я вижу из этого метода, заключается в том, что вы должны реализовать каждый абстрактный метод в TestDerivedHelper, но он дает вам больше контроля позже.

надеюсь, что это помогает. ;)

причина, по которой это невозможно, связана с тем, как параметры "магически" создаются C#. Когда вы определяете параметр, C# создает private поле, которым манипулируют неявные геттер и сеттер. Если в базовом классе нет сеттера, невозможно изменить эту переменную из метода, записанного в подклассе (поскольку частный флаг запрещает доступ к нему даже подклассам). Обычно он использует неявный сеттер базового класса вместо.

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

осада

abstract class TestBase
{
    public abstract int Int { get; }
}

class TestDerivedHelper : TestBase
{
    private int _Int;
    public override int Int
    {
        get
        {
            return _Int;
        }
    }

    protected void SetInt(int value)
    {
        this._Int = value;
    }
}

class TestDerived : TestDerivedHelper
{
    public new int Int
    {
        get { return base.Int; }
        set { base.SetInt(value); }
    }
}

С помощью TestDerived будет иметь функциональность, которую вы ищете. Этот единственный недостаток я вижу из этого метода заключается в том, что вы должны реализовать каждый абстрактный метод в TestDerivedHelper, но это дает вам больше контроль позже.

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

несмотря на то, что эта тема старая, я ставлю свое решение, если это кому-то поможет. Это не мое собственное, но основано на ответах в других темах SO.

public abstract BaseClass
{
  public double MyPoP { get { return GetMyPoP; } }

  protected abstract double GetMyPoP { get; }
}

public class DClass: BaseClass
{
  public new double MyPoP { get; set; }

  protected override double GetMyPop { get { return MyPoP; } }
}

Это решение добавляет дополнительную строку кода для каждого такого свойства, что требует доступа изменены. Тем не менее, нет никаких изменений во внешней видимости и обеспечивает необходимую функциональность.

public abstract class BaseClass
{
    public abstract double MyPop { get; }
}

public class DClass: BaseClass
{
    private double _myPop = 0;
    public override double MyPop 
    {
        get { return _myPop; }
    }

    // some other methods here that use the _myPop field
}

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

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

нельзя переопределить метод доступа set, так как базовый класс не имеет определенного метода доступа set.

что вы можете сделать, это использовать new ключевое слово, чтобы скрыть реализацию базовых классов, но это может быть не то, что вы хотите.

EDIT:

хорошо, я, возможно, был поспешен с этим ответом, но я дал ему еще немного подумать.

вы должны использовать абстрактный базовый класс? Если это не требуется, попробуйте это:

public interface ISomeRelevantName
{
    double MyPop { get; }
}

public class DClass : ISomeRelevantName
{
    public double MyPop { get; set; }
}