В одном из моих заданий в начале 90-х, мы использовали .cc и .hh для исходных и заголовочных файлов соответственно. Я все еще предпочитаю его по всем альтернативам, вероятно, потому что является самым легким ввести.
В приведенном вами примере пользовательский интерфейс проверяет вводимые данные.
Таким образом, хороший подход - отделить валидацию от действия. WinForms имеет встроенную систему проверки, но в принципе она работает следующим образом:
ValidationResult v = ValidateName(string newName);
if (v == ValidationResult.NameOk)
SetName(newName);
else
ReportErrorAndAskUserToRetry(...);
Кроме того, вы можете применить проверку в методе SetName, чтобы убедиться, что валидность проверена:
public void SetName(string newName)
{
if (ValidateName(newName) != ValidationResult.NameOk)
throw new InvalidOperationException("name has not been correctly validated");
name = newName;
}
(Обратите внимание, что это может не лучший подход к производительности, но в ситуации применения простой проверки валидации к вводу пользовательского интерфейса маловероятно, что двойная валидация будет иметь какое-либо значение. В качестве альтернативы, вышеуказанная проверка может быть выполнена исключительно как утверждение только для отладки check, чтобы отловить любую попытку программистов вызвать метод без предварительной проверки ввода. Как только вы узнаете, что все вызывающие абоненты соблюдают свой контракт, часто нет необходимости в проверке времени выполнения выпуска вообще)
Процитируем другой ответ:
Either a member fulfills its contract or it throws an exception. Period.
Здесь упускается следующее: что такое контракт? Совершенно разумно указать в «контракте», что метод возвращает значение статуса. например File.Exists () возвращает код состояния, а не исключение, потому что это его контракт.
Однако ваш пример другой. В нем вы фактически выполняете два отдельных действия: проверку и сохранение. Если SetName может либо вернуть код состояния , либо установить имя, он пытается выполнить две задачи в одной, что означает, что вызывающий никогда не знает, какое поведение он будет демонстрировать, и должен иметь особую обработку случаев для те случаи. Однако, если вы разделите SetName на отдельные шаги Validate и Store, тогда контракт для StoreName может заключаться в том, что вы передаете действительные входные данные (как передано ValidateName), и он генерирует исключение, если этот контракт не выполняется. Поскольку каждый метод затем выполняет одно и только одно действие, контракт очень ясен, и очевидно, когда должно быть создано исключение.
Я предполагаю, что вы создаете свой собственный механизм проверки бизнес-правил, поскольку вы не упомянули тот, который используете.
Я бы использовал исключения, но я бы не стал их бросать . Очевидно, вам нужно будет где-то накапливать состояние оценки - чтобы зафиксировать факт сбоя определенного правила, я бы сохранил экземпляр Exception, описывающий сбой. Это происходит потому, что:
Сообщение
, удобочитаемое человеком, и могут иметь дополнительные свойства для записи деталей исключения в машиночитаемой форме. FormatException
. Вы можете перехватить это исключение и добавить его в список. Фактически,
Думаю, у вас неправильное впечатление о предполагаемом сообщении. Вот отличная цитата, которую я вчера встретил из текущего выпуска журнала Visual Studio (Том 19, № 8).
Либо участник выполняет свой контракт, либо выдает исключение. Период. Нет золотой середины. Никаких кодов возврата, нет, иногда это работает, иногда нет.
Исключения следует использовать с осторожностью, поскольку их создание и выбрасывание дорого, но они, однако, являются способом .NET framework для уведомления клиента ( под этим я подразумеваю любой вызывающий компонент) ошибки.
Я согласен с частью предложения Хенка.
Традиционно операции «прошел / не прошел» были реализованы как функции с целочисленным или логическим типом возвращаемого значения, которые указывали бы результат вызова. Однако некоторые возражают против этого, заявляя, что «функция или метод должны либо выполнять действие, либо возвращать значение, но не то и другое вместе». Другими словами, член класса, который возвращает значение, не должен также быть членом класса, который изменяет состояние объекта.
Я нашел лучшее решение, добавив .HasErrors / .IsValid и . Errors свойство внутри класса, генерирующего ошибки. Первые два свойства позволяют клиентскому классу проверять, существуют ли ошибки, и, если необходимо, также может читать свойство .Errors и сообщать об одной или всех содержащихся ошибках. Затем каждый метод должен знать об этих свойствах и соответствующим образом управлять состоянием ошибки. Эти свойства затем можно преобразовать в интерфейс IErrorReporting, который могут включать различные классы фасадов уровня бизнес-правил.
Исключения - это просто способ обработки исключительных сценариев, сценариев, которые обычно не должны происходить в вашем приложении. Оба представленных примера являются разумными примерами того, как правильно использовать исключения. В обоих случаях они идентифицируют, что было вызвано действие, выполнение которого не должно быть разрешено и является исключительным для нормального потока приложения.
Неправильная интерпретация заключается в том, что вторая ошибка, метод переименования, только механизм для обнаружения ошибки переименования. Исключения никогда не должны использоваться в качестве механизма передачи сообщений в пользовательский интерфейс. В этом случае у вас будет некоторая логика, проверяющая, что имя, указанное для переименования, действительно где-то в вашей проверке пользовательского интерфейса. Эта проверка сделает так, чтобы исключение никогда не было частью обычного потока.
Исключения предназначены для предотвращения «плохих вещей», они действуют как последняя линия защиты для ваших вызовов API, чтобы гарантировать, что ошибки будут остановлены и что может иметь место только законное поведение. Это ошибки на уровне программиста, и они должны указывать только на одно из следующих событий:
Они не должны быть единственной линией защиты от ошибок пользователя. Пользователям требуется гораздо больше отзывов и внимания, чем может предложить какое-либо исключение, и они будут регулярно они выступают в качестве последней линии защиты для ваших вызовов API, чтобы гарантировать, что ошибки будут устранены и что может иметь место только законное поведение. Это ошибки на уровне программиста, и они должны указывать только на одно из следующих событий:
Они не должны быть единственной линией защиты от ошибок пользователя. Пользователям требуется гораздо больше отзывов и внимания, чем может предложить какое-либо исключение, и они будут регулярно они выступают в качестве последней линии защиты для ваших вызовов API, чтобы гарантировать, что ошибки будут устранены и что может иметь место только законное поведение. Это ошибки на уровне программиста, и они должны указывать только на одно из следующих событий:
Они не должны быть единственной линией защиты от ошибок пользователя. Пользователям требуется гораздо больше отзывов и внимания, чем может предложить какое-либо исключение, и они будут регулярно
Они не должны быть единственной линией защиты от ошибок пользователя. Пользователям требуется гораздо больше отзывов и внимания, чем может предложить какое-либо исключение, и они будут регулярно
Они не должны быть единственной линией защиты от ошибок пользователя. Пользователям требуется гораздо больше отзывов и внимания, чем может предложить какое-либо исключение, и они будут регулярно пытаться делать вещи, выходящие за рамки ожидаемого потока ваших приложений.
На мой взгляд, если есть сомнения, выбрасывайте исключения при проверке бизнес-правил. Я знаю, что это несколько нелогично, и я могу разозлиться на этом, но я стою за это, потому что то, что является рутинным, а что нет, зависит от ситуации и является бизнес-решением, а не программным.
Например, если у вас есть классы бизнес-домена, которые используются приложением WPF и службой WCF, недопустимый ввод поля может быть обычным делом в приложении WPF, но это будет иметь катастрофические последствия, если объекты домена используются в Ситуация WCF, когда вы обрабатываете запросы на обслуживание от другого приложения.
Я долго и упорно думал, и пришел к этому решению. Выполните следующие действия с классами домена: