Переопределить получить, но не установить - PullRequest
71 голосов
/ 08 января 2010

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

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

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

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

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

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

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

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

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

Ответы [ 13 ]

25 голосов
/ 08 января 2010

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

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

public void SetMyPop(double value)
{
    _myPop = value;
}
17 голосов
/ 08 января 2010

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

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

public interface IBaseInterface
{
    double MyPop { get; }
}

public class DClass : IBaseInterface
{
    public double MyPop { get; set; }
}
11 голосов
/ 25 февраля 2017

Новое в 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;}
}
8 голосов
/ 08 января 2010

Если 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; }
    }
}

РЕДАКТИРОВАТЬ: Затем вы можете сделать публичный метод в DClass SetMyProp(double myProp) или тому подобное. Дизайн класса для вашей доменной модели должен быть понятен или говорить сам за себя, почему вы не можете установить свойство непосредственно в базовом классе и почему вы можете сделать это в производном.

5 голосов
/ 08 января 2010

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

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

2 голосов
/ 13 июля 2015

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

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

2 голосов
/ 08 января 2010

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

abstract class TestBase { public abstract int Int { get; } }</p> <pre><code>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, но это даст вам больше контроля позже.

Надеюсь, это поможет. ;)

1 голос
/ 27 июня 2017

Несмотря на то, что эта ветка старая, я предлагаю свое решение, если оно кому-нибудь поможет. Это не мое, но основано на ответах в других темах 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; } }
}

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

1 голос
/ 28 июня 2013

Осада

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.

0 голосов
/ 08 января 2010
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, тогда, возможно, было бы лучше поместить установщик в базовый класс.

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