Как указать, что метод был неудачным - PullRequest
13 голосов
/ 02 октября 2008

У меня есть несколько похожих методов, скажем, например. CalculatePoint (...) и CalculateListOfPoints (...). Иногда они не могут быть успешными, и должны указать это вызывающей стороне. Для CalculateListOfPoints, которая возвращает общий список, я мог бы вернуть пустой список и потребовать, чтобы вызывающий проверил это; однако Point является типом значения, поэтому я не могу вернуть значение null.

В идеале я бы хотел, чтобы методы выглядели одинаково; Одним из решений может быть определение их как

public Point CalculatePoint(... out Boolean boSuccess);
public List<Point> CalculateListOfPoints(... out Boolean boSuccess);

или в качестве альтернативы вернуть балл? для CalculatePoint и возвращаемое значение NULL для обозначения ошибки. Это означало бы необходимость возврата к ненулевому типу, что кажется чрезмерным.

Другим способом было бы вернуть логическое значение boSuccess, иметь результат (Point или List) в качестве параметра 'out' и вызывать их TryToCalculatePoint или что-то ...

Что такое лучшая практика?

Редактировать: я не хочу использовать исключения для управления потоком! Иногда ожидается сбой.

Ответы [ 16 ]

24 голосов
/ 02 октября 2008

Лично я думаю, что использовал бы ту же идею, что и TryParse (): использование параметра out для вывода реального значения и возвращение логического значения, указывающего, был ли вызов успешным или нет

public bool CalculatePoint(... out Point result);

Я не фанат использования исключений для "нормального" поведения (если вы ожидаете, что функция не будет работать для некоторых записей).

7 голосов
/ 02 октября 2008

Почему они потерпят неудачу? Если это из-за чего-то, что сделал вызывающий (то есть предоставленные аргументы), тогда выбрасывание ArgumentException вполне уместно. Метод Try [...], позволяющий избежать исключения, вполне подходит.

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

5 голосов
/ 02 октября 2008

Другая альтернатива - бросить исключение. Однако вы, как правило, хотите генерировать исключения только в «исключительных случаях».

Если случаи сбоев являются общими (и не исключительными), то вы уже перечислили два варианта. РЕДАКТИРОВАТЬ : в вашем проекте может быть соглашение о том, как обрабатывать такие неисключительные случаи (следует ли возвращать успех или объект). Если соглашение отсутствует, я согласен с lucasbfr и предлагаю вам вернуть успех (что согласуется с тем, как спроектирован TryParse (...)).

2 голосов
/ 02 октября 2008

Если сбой произошел по определенной причине, то я думаю, что можно вернуть значение null или bool и иметь параметр out. Однако, если вы возвращаете ноль независимо от ошибки, я не рекомендую это делать. Исключения предоставляют обширный набор информации, в том числе причину, ПОЧЕМУ что-то не удалось, если все, что вы получили, является нулевым, то как вы узнаете, если это из-за неправильных данных, у вас закончилась память или другое странное поведение. *

Даже в .net у TryParse есть брат Parse, так что вы можете получить исключение, если хотите.

Если бы я предоставил метод TrySomething, я бы также предоставил метод Something, который вызывал исключение в случае сбоя. Тогда дело за абонентом.

1 голос
/ 02 октября 2008

Шаблон, с которым я экспериментирую, возвращает Возможно . Он имеет семантику шаблона TryParse , но аналогичен сигнатуре с шаблоном null-return-on-error.

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

Класс Maybe выглядит примерно так:

/// <summary>
/// Represents the return value from an operation that might fail
/// </summary>
/// <typeparam name="T"></typeparam>
public struct Maybe<T>
{
    T _value;
    bool _hasValue;


    public Maybe(T value)
    {
        _value = value;
        _hasValue = true;
    }

    public Maybe()
    {
        _hasValue = false;
        _value = default(T);
    }


    public bool Success
    {
        get { return _hasValue; }
    }


    public T Value
    {
        get 
            { // could throw an exception if _hasValue is false
              return _value; 
            }
    }
}
1 голос
/ 02 октября 2008

Возврат Точка. Пустая . Это шаблон проектирования .NET, возвращающий специальное поле, когда вы хотите проверить, было ли создание структуры успешным. Избегайте out параметров, когда можете.

public static readonly Point Empty
1 голос
/ 02 октября 2008

Это в основном зависит от поведения ваших методов и их использования.

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

Если сбой неожиданный, вернуть результат напрямую и передать ошибки с исключениями. Хорошим кандидатом может быть открытие файла только для чтения, подключение к TCP-серверу.

И иногда оба пути имеют смысл ...

1 голос
/ 02 октября 2008

Подводя итог, можно выделить несколько подходов:

  1. Когда тип возвращаемого значения является типом значения, например Point, используйте функцию Nullable в C # и вернуть Point? (он же Nullable), таким образом, вы все равно можете вернуть ноль при ошибке
  2. Бросить исключение при сбое. Весь спор / дискуссия о том, что является и не является «исключительным», является спорным вопросом, это ваш API, вы решаете, что такое исключительное поведение.
  3. Примите модель, аналогичную модели, реализованной Microsoft в базовых типах, таких как Int32, предоставьте CalculatePoint и TryCalculatePoint (int32.Parse и int32.TryParse) и сделайте один бросок, а другой вернёт логическое значение.
  4. Возвращает обобщенную структуру из ваших методов, которая имеет два свойства: bool Success и GenericType Value.

В зависимости от сценария я склонен использовать комбинацию возврата нуля или генерирования исключения, поскольку они кажутся мне «самыми чистыми» и лучше всего соответствуют существующей базе кода в компании, в которой я работаю. Таким образом, моя личная лучшая практика будет подходы 1 и 2.

1 голос
/ 02 октября 2008

Модель, которую я использовал, та же самая, что MS использует с методами TryParse различных классов.

Ваш оригинальный код:
Public Point CalculatePoint (... out Boolean boSuccess);
открытый список CalculateListOfPoints (... out Boolean boSuccess);

Превратится в public bool CalculatePoint (... out (или ref) Point CalculatedValue);
public bool CalculateListOfPoints (... out (или ref) Список CalculatedValues);

В основном вы делаете успех / неудачу возвращаемым значением.

0 голосов
/ 08 октября 2008

Извините, я только что вспомнил тип Nullable, вы должны посмотреть на это. Хотя я не совсем уверен, что это за издержки.

...