Подтвердить что ты не робот

Как указать, что метод не увенчался успехом

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

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

Исходный код:
public Point CalculatePoint (... из Boolean boSuccess);
открытый список CalculateListOfPoints (... out Boolean boSuccess);

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

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

Ответ 6

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

  • Когда тип возвращаемого значения является типом значения, например Point, использует функцию Nullable С# и возвращает точку? (иначе Nullable), таким образом вы все равно можете вернуть null при сбое
  • Выбросить исключение, если произошел сбой. Весь аргумент/обсуждение относительно того, что есть и не является "исключительным", является спорным вопросом, это ваш API, вы решаете, какое исключительное поведение.
  • Примите модель, аналогичную той, которая реализована Microsoft в базовых типах, таких как Int32, предоставит CalculatePoint и TryCalculatePoint (int32.Parse и int32.TryParse) и имеет один бросок и один возвращает bool.
  • Возвращает общую структуру из ваших методов, которая имеет два свойства: bool Success и значение GenericType.

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

Ответ 7

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

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

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

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

Ответ 8

Вернуть Point.Empty. Это .NET-проект, чтобы вернуть специальное поле, если вы хотите проверить, было ли создание структуры успешным. Избегайте параметров, когда сможете.

public static readonly Point Empty

Ответ 9

Образец, с которым я экспериментирую, возвращает Maybe. Он имеет семантику шаблона 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; 
            }
    }
}

Ответ 10

Я бы сказал, что наилучшей практикой является возвращаемое значение - это успех, а exception означает сбой.

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

Ответ 11

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

// NB:  A bool is the return value. 
//      This makes it possible to put this beast in if statements.
public bool TryCalculatePoint(... out Point result) { }

public Point CalculatePoint(...)
{
   Point result;
   if(!TryCalculatePoint(... out result))
       throw new BogusPointException();
   return result;
}

Лучшее из обоих миров!

Ответ 12

Bool TrySomething() - это, по крайней мере, практика, которая работает нормально для методов анализа .net, но я не думаю, что мне это нравится вообще.

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

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

Однако - ваш подход является немного процедурным - как насчет создания чего-то вроде класса PointCalculator - взятия требуемых данных в качестве параметров в конструкторе? Затем вы вызываете CalculatePoint на него и получаете доступ к результатам через свойства (отдельные свойства для точки и для успеха).

Ответ 13

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

Вы должны вернуть то, что ожидается для "сбоя", как правило, null - это мой выбор плохого возврата.

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

Ответ 14

Мы когда-то написали всю Структуру, где все общедоступные методы либо вернули true (выполнено успешно), либо false (произошла ошибка). Если нам нужно было вернуть значение, мы использовали выходные параметры. Вопреки распространенному мнению, этот способ программирования фактически упростил много нашего кода.

Ответ 15

Хорошо с точкой, вы можете отправить обратно Point.Empty в качестве возвращаемого значения в случае отказа. Теперь все это действительно возвращает точку с 0 для значений X и Y, поэтому, если это может быть допустимым возвращаемым значением, я бы держался подальше от этого, но если ваш метод никогда не вернет точку (0,0), то вы можете использовать это.

Ответ 16

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