Хорошая практика при обработке исключений в C # - PullRequest
7 голосов
/ 07 мая 2011

Я читал в The Pragmatic Programmer и в некоторых других статьях (в том числе в статье Джоэла Спольски), что вы должны выбрасывать исключения только в исключительных случаях.В противном случае вы должны вернуть ошибку.

Иногда это возможно (возвращая, например, -1, -0 или positive number), но в других случаях это невозможно.Я имею в виду, что если вы возвращаете класс, вы всегда можете вернуть null, но я думаю, что идея состоит в том, чтобы вернуть что-то, что предупредит вызывающего абонента о том, что произошло.

Если я всегда возвращаю null, я не думаю, что было бы полезно сказать: Если этот метод возвращает ноль, это может быть из-за A, B, C, D или E

Итак, как именно это можно реализовать в C #?

Редактировать:
Через несколько часов после того, как я разместил этот вопрос, яЗдесь я увидел другой вопрос, в котором сам вопрос был о том, был ли опубликованный код хорошей практикой или нет.

Я вижу, что это еще один способ сделать то, что я здесь спрашивал.Вот ссылка:

Общие недостатки имущества?

Ответы [ 7 ]

12 голосов
/ 07 мая 2011

Гораздо лучшим правилом для того, когда генерировать исключения, является следующее:

Бросьте исключение, когда ваш метод не может сделать то, что его имя говорит, что он делает.

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

Правило «выбрасывать исключения только в исключительных случаях» является бесполезным вафельным IMO, поскольку оно не дает вам эталона для определения того, что является исключительным, а что нет.Это все равно что сказать: «Ешьте только пищу, которая съедобна».

10 голосов
/ 07 мая 2011

Используя цифры, вы прямо противоречите рекомендациям Microsoft с исключениями. Лучший источник информации, который я обнаружил, который лишает мистики весь предмет, - это CLR Джеффри Рихтера через C # 3 . Также стоит прочитать книгу .NET Framework Guidelines за материал об исключениях.

Цитировать MSDN :

Не возвращать коды ошибок. Исключения являются основным средством сообщения об ошибках в рамках.

Одним из решений, которое вы можете принять, является параметр out, который получает результат. Затем ваш метод возвращает bool очень похоже на множество TryParse методов, которые вы встречаете в рамках.

8 голосов
/ 07 мая 2011

Один пример для рассмотрения - int.TryParse.При этом используется проанализированный параметр out, а возвращаемое значение bool указывает на успех или неудачу.bool можно заменить перечислением или более сложным объектом, если ситуация этого заслуживает.(Например, проверка данных может завершиться сбоем таким образом, что действительно потребует сбора сбоев и т. были:

public static Tuple<int, bool> TryParse(string text)

Следующая возможность состоит в том, чтобы иметь объект, инкапсулирующий весь результат, включая режим сбоя, если это необходимо.Например, вы можете запросить у Task<T> его результат, его статус и исключение, если он потерпел неудачу.

Все это уместно, только если это не ошибка произойти, как таковой.Это не указывает на ошибку, просто что-то вроде плохого пользовательского ввода.Я действительно не люблю возвращать коды ошибок - исключения гораздо более идиоматичны в .NET.

1 голос
/ 07 мая 2011

Джоэл Спольски не прав.Возвращение статуса с помощью кодов ошибок / возврата означает, что вы не можете доверять результатам любого вызова метода - возвращаемое значение должно быть проверено и обработано.

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

Затем этот код, предполагая, что контракт Method1 () и Method2 () должен либо успешно выполнить, либо выдать исключение, имеет 1 возможный поток через него .:

foo.Method(...) ;
bar.Method(...) ;

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

bool fooSuccess = foo.Method(...);
if ( fooSuccess )
{
  bool barSuccess = bar.Method(...);
  if ( barSuccess )
  {
    // The normal course of events -- do the usual thing
  }
  else
  {
    // deal with bar.Method() failure
  }
}
else // foo.Method() failed
{
  // deal with foo.Method() failure
}

Возврат кодов состояния вместо выдачи исключений

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

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

Обеспечить выполнение контрактов вашегоМетод:

  • Предварительные условия. Вызывающий гарантирует, что они верны до вызова метода.
  • Постусловия. Callee гарантирует, что это правдаследующий вызов метода.
  • Инвариантные условия. Callee гарантирует, что они всегда верны.

Бросьте исключение, если контракт нарушен.Затем выведите исключение, если произойдет что-то неожиданное.

Ваш код должен быть строгим дисциплинарным.

1 голос
/ 07 мая 2011

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

// Exception
public void Connect(Options o); 

// Error Code
public bool TryConnect(Options o, out Error e); 
1 голос
/ 07 мая 2011

Microsoft документировала лучшие практики по обработке ошибок в .NET

http://msdn.microsoft.com/en-us/library/8ey5ey87(VS.71).aspx

Я бы рекомендовал следовать этим рекомендациям, поскольку это стандарт для .NET, и у вас будет гораздо меньше конфликтов с другими разработчиками .NET.

(Обратите внимание, я понимаю, что разместил более старую ссылку, но рекомендации остались.)

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

0 голосов
/ 07 мая 2011

Я возвращаю такие значения как null ссылки или отрицательные значения индекса, только если я уверен, что не будет недопонимания, когда код будет использоваться другим разработчиком. Что-то вроде функции LINQ IEnumerable<T>.FirstOrDefault. IEnumerable<T>.First выдает исключение для пустых коллекций, поскольку ожидается, что он вернет первый элемент, а пустая коллекция - исключительный случай

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