Какое исключение выбрасывать, когда средство настройки свойств не разрешено?

У меня есть базовый класс, обладающий виртуальным свойством:

public virtual string Name { get; set; }

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

public override string Name
{
    get { return "Fixed Name"; }
}

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

Поэтому я подумал, что сделаю что-то вроде:

public override string Name
{
    get { return "Fixed Name"; }
    set { throw new Exception(); } //which exception type?
}

Итак, два (связанные вопросы):

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

Изменить: некоторые причины, по которым одно исключение было бы предпочтительнее другого, были бы хороши. У моего коллеги и у меня были те же аргументы между NotSupported и InvalidOperation.

Ответ 1

Выбросить исключение NotSupportedException. Цитата из ссылки:

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

Мое мнение таково, что InvalidOperationException не является правильным вариантом. Цитата из MSDN:

Исключение, которое вызывается, когда вызов метода недействителен для текущего состояния объекта.

В вашей ситуации нет ничего о текущем состоянии. Дело в том, что контракт класса не поддерживает операцию.

Ответ 2

Это ломает принцип замены Лискова и то, почему это плохая идея.

Ответ 3

Если вы можете попытаться переместить setter в конструктор базового класса и сделать setter частным. Или как Джон предложил создать абстрактный базовый класс/интерфейс с геттерами, которые поддерживаются во всех реализациях.

Это позволило бы избежать ситуации с выбросом исключения.

Ответ 4

Если базовый класс фактически позволяет установить имя (в отличие от выставления абстрактного сеттера, который не гарантированно работает), производные классы должны это делать. Если вы хотите, чтобы иерархия включала в себя некоторые классы, в которых имя может быть задано, а некоторые, где это невозможно, оба класса должны наследоваться от абстрактного класса ReadableXX с не виртуальным read-write Name которое GetName SetName методы GetName и SetName, Он также должен предоставить некоторые средства, указывающий SetName будет поддерживаться (например, CanSetName метод). Только для чтения вариант класса можно определить "новое" только для чтения Name свойства, которое бы цепью к GetName и иметь SetName переопределение бросок NotSupportedException. Если спецификация класса говорит о том, что SetName будет работать только в том случае, если CanSetName возвращает true, то с помощью SetName исключение в классах, где CanSetName возвращает false, не будет нарушать Принцип замещения Лискова.