Почему невозможно переопределить свойство только для метода считывания и добавить метод set? [закрытый]

Указатель NULL - это тот, который указывает на никуда. Когда вы разыскиваете указатель p, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p является нулевым указателем, местоположение, хранящееся в p, является nowhere, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception.

В общем, это потому, что что-то не было правильно инициализировано.

139
задан 10 revs, 5 users 79% 28 December 2018 в 12:53
поделиться

8 ответов

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

я с Microsoft на этом.
Скажем, я - новый программист, которому сказали кодировать против деривации Базового класса. я пишу что-то, что предполагает, что Панель не может быть записана в (так как Базовый класс явно указывает, что это - получение только свойства). Теперь с Вашей деривацией, мой код может повредиться. например,

public class BarProvider
{ BaseClass _source;
  Bar _currentBar;

  public void setSource(BaseClass b)
  {
    _source = b;
    _currentBar = b.Bar;
  }

  public Bar getBar()
  { return _currentBar;  }
}

, Так как Панель не может быть установлена согласно интерфейсу BaseClass, BarProvider предполагает, что кэширование является безопасной вещью сделать - Так как Панель не может быть изменена. Но если бы установленный было возможно в деривации, то этот класс мог бы служить устаревшим значениям, если бы кто-то изменил свойство Bar _source объекта внешне. Так как точка будь' Быть Открытой, постарайтесь не делать подлые вещи и удивлять людей '

Обновление : Ilya Ryzhenkov спрашивает, 'Почему интерфейсы не играют по тем же правилам затем?' Хм.. это становится более грязным, как я думаю об этом.
интерфейс является контрактом, в котором говорится, 'ожидают, что реализация будет иметь свойство чтения под названием Панель'. Лично я гораздо менее вероятен для создания того предположения о только для чтения, если я видел Интерфейс. Когда я вижу свойство только добирания в интерфейсе, я считал его, поскольку 'Любая реализация выставит эту Панель атрибута'... на базовом классе это нажимает, поскольку 'Панель является свойством только для чтения'. Конечно, технически Вы не нарушаете условия контракта.. Вы делаете больше. Таким образом, Вы правы в некотором смысле.. Я был бы рядом с высказыванием 'делать его максимально трудно, чтобы недоразумения неожиданно возникли'.

0
ответ дан 23 November 2019 в 23:23
поделиться

Поскольку класс, который имеет свойство только для чтения (никакой метод set), вероятно, имеет серьезное основание для него. Не могло бы быть никакого базового хранилища данных, например. Разрешение Вам создать метод set нарушает условия контракта, сформулированные классом. Это - просто плохое ООП.

-1
ответ дан 23 November 2019 в 23:23
поделиться

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

-1
ответ дан 23 November 2019 в 23:23
поделиться

Поскольку на уровне IL, свойство чтения/записи переводит в два (метод считывания и метод set) методы.

При переопределении, необходимо продолжать поддерживать базовый интерфейс. Если бы Вы могли бы добавить метод set, Вы эффективно добавили бы новый метод, который остался бы невидимым для внешнего мира, что касается интерфейса Ваших классов.

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

-1
ответ дан 23 November 2019 в 23:23
поделиться

Я могу понять все Ваши точки, но эффективно, C# 3.0's автоматические свойства становятся бесполезными в этом случае.

Вы не можете сделать ничего как этот:

public class ConcreteClass : BaseClass
{
    public override int Bar
    {
        get;
        private set;
    }
}

IMO, C# не должен ограничивать такие сценарии. Это - обязанность разработчика использовать его соответственно.

1
ответ дан 23 November 2019 в 23:23
поделиться

Вы могли, возможно, обойти проблему путем создания нового свойства:

public new int Bar 
{            
    get { return 0; }
    set {}        
}

int IBase.Bar { 
  get { return Bar; }
}
1
ответ дан 23 November 2019 в 23:23
поделиться

Я думаю, что основная причина просто в том, что синтаксис слишком явный, чтобы это работало по-другому. Этот код:

public override int MyProperty { get { ... } set { ... } }

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

Вы можете сказать, что компилятор должен угадать ваше намерение и применить переопределение только к методу, который можно переопределить (то есть к получателю в данном случае), но это противоречит одному из принципов проектирования C # - компилятор не должен угадать свои намерения, потому что он может угадать неверно без вашего ведома.

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

public int MyProperty
{
    override get { ... }
    set { ... }
}

или, для автореализуемых свойств,

public int MyProperty { override get; set; }
37
ответ дан 23 November 2019 в 23:23
поделиться

Это не невозможно. Вам просто нужно использовать ключевое слово «новое» в своей собственности. Например,

namespace {
    public class Base {
        private int _baseProperty = 0;

        public virtual int BaseProperty {
            get {
                return _baseProperty;
            }
        }

    }

    public class Test : Base {
        private int _testBaseProperty = 5;

        public new int BaseProperty {
            get {
                return _testBaseProperty;
            }
            set {
                _testBaseProperty = value;
            }
        }
    }
}

Похоже, что этот подход удовлетворяет обе стороны этого обсуждения. Использование «нового» нарушает договор между реализацией базового класса и реализацией подкласса. Это необходимо, когда класс может иметь несколько контрактов (через интерфейс или базовый класс).

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

-2
ответ дан 23 November 2019 в 23:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: