Какое исключение выбрасывать, когда средство настройки свойств не разрешено?
У меня есть базовый класс, обладающий виртуальным свойством:
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?
}
Итак, два (связанные вопросы):
- Есть ли лучший образец для меня?
- Если я должен использовать приведенный выше шаблон, какое исключение использовать?
Изменить: некоторые причины, по которым одно исключение было бы предпочтительнее другого, были бы хороши. У моего коллеги и у меня были те же аргументы между 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, не будет нарушать Принцип замещения Лискова.
Ответ 5
Здесь я бы выбрал NotImplementedException.