TryFoo должен когда-либо выдавать исключение?

Различие находится, прежде всего, в развертывании. Сеть вперед и реверс проксируют, у всех есть те же базовые функции, они принимают запросы на Запросы HTTP в различных форматах и обеспечивают ответ, обычно путем доступа к источнику или серверу контакта.

Полнофункциональные серверы обычно имеют управление доступом, кэширование и некоторые отображающие ссылку функции.

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

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

На самом деле, единственный экземпляр прокси может работать как вперед и инвертировать прокси одновременно для различного клиентского населения.

Это - короткая версия, я могу разъясниться, хотят ли люди прокомментировать.

8
задан Community 23 May 2017 в 12:01
поделиться

11 ответов

Это зависит от ситуации. TryParseFoo должен перехватывать все исключения синтаксического анализа для таких вещей, как пустые или неверно отформатированные строки. Но есть также несвязанные исключения ( ThreadAbortException , скажем), которые не должны подавляться автоматически.

В Python (терпите меня) вы можете вызвать много проблем, перехватив KeyboardInterrupt ], что в основном означает, что ваша программа продолжает работать, даже если вы нажмете Ctrl-C.

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

5
ответ дан 5 December 2019 в 07:36
поделиться

Это не гарантия отсутствия исключений. Рассмотрим этот тривиальный пример в Dictionary ...

var dic = new Dictionary<string, string>() { { "Foo", "Bar" } };

string val = String.Empty;
string key = null;

dic.TryGetValue(key, out val); // oops

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

private int FindEntry(TKey key)
{
  if (key == null)
  {
    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
   }
   // more stuff
}

На мой взгляд, смысл контракта - «Если то, что вы пытались сделать, не удалось, я не буду генерировать исключение», но это далеко от «Я не буду генерировать никаких исключений» . " Поскольку вы, вероятно, не пишете фреймворк, вы можете пойти на компромисс с чем-то вроде этого ...

catch( Exception ex )
{
  Logger.Log( ex );
  Debug.Assert( false );
  foo = null;
  return false;
}  

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

5
ответ дан 5 December 2019 в 07:36
поделиться

Я не думаю, что TryFoo не должен генерировать исключения. Я думаю, что контракт TryFoo заключается в том, что он будет обрабатывать недопустимый ввод как нормальный случай, а не как исключительный. То есть он не вызовет исключения, если не сможет выполнить свою задачу из-за недопустимого ввода; если он не работает по какой-либо другой причине, он должен вызвать исключение. Я ожидал, что после возврата TryFoo либо он обработал мой ввод, либо мой ввод был недействительным . Если ни одно из этих утверждений не соответствует действительности, мне нужно исключение, поэтому я знаю об этом.

3
ответ дан 5 December 2019 в 07:36
поделиться

Два других вопроса о StackOverflow, на которые вы связались, кажутся настоящими ошибками. Тот, где Uri.TryCreate , например, выдает исключение UriFormatException, определенно является нарушением контракта, поскольку в документации MSDN для этого метода явно указано:

Не генерирует исключение, если Uri не может быть создан.

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

Как правило, будет две версии этого вида методов: одна, которая генерирует исключения, и тот, который этого не делает. Например, Int32.Parse и Int32.TryParse . Суть метода TryXXX не в том, чтобы скрыть исключения. Это для ситуаций, когда отказ на самом деле не является исключительным условием. Например, если вы читаете число с консоли и хотите продолжать попытки до тех пор, пока не будет введено правильное число, вы не хотите перехватывать исключения. Точно так же, если вы хотите получить значение из словаря, но это совершенно нормальный случай, когда оно может не существовать, вы должны использовать TryGetValue .

Резюме : TryXXX не должен генерировать исключения, и он также не предназначен для скрытия исключений. Это для случаев, когда сбой является нормальным и неисключительным, и вы хотели бы легко обнаружить этот случай без накладных расходов и усилий по перехвату исключения. Обычно это не метод TryXXX,

2
ответ дан 5 December 2019 в 07:36
поделиться

Вы почти никогда не должны перехватывать все исключения. Если вы должны реализовать TryXXX , используя пару try / catch вокруг XXX (вместо предпочтительной, XXX реализованной в терминах TryXXX и выдачи ложного результата), перехватить только конкретное ожидаемое исключение (я).

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

1
ответ дан 5 December 2019 в 07:36
поделиться

Идея, лежащая в основе TryXXX , заключается в том, что он не генерирует исключение определенного типа, которое обычно возникает, если вы просто вызываете соответствующий вызов XXX - потребитель метода знает, что они игнорируют любые исключения, которые обычно возникают.

Это заманчиво, потому что это гарантирует, что никакие исключения не исчезнут, тем самым соблюдая подразумеваемый контракт.

Это не совсем так - есть несколько исключения, которые могут избежать try / catch (например, OutOfMemoryException , StackOverflowException и т. д.).

1
ответ дан 5 December 2019 в 07:36
поделиться

Это зависит от того, что пытается сделать метод.

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

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

1
ответ дан 5 December 2019 в 07:36
поделиться

Но если TryFoo позволяет избежать некоторых исключений, то на самом деле он говорит: «Я не буду генерировать исключения, которые я знаю, как обрабатывать», а затем вся идея контракта » Я не буду генерировать исключения "выброшено в окно.

Я думаю, вы сами это сказали:)

TryXXX должен только гарантировать, что он не будет генерировать исключения, которые он знает, как обрабатывать. Если он не знает, как обработать данное исключение, зачем ему его перехватывать? То же самое и с вами - если вы не знаете, что делать, зачем вам это ловить? BadAllocExceptions, например, ну (обычно) с ними нечего делать, кроме как поймать их в главном блоке try / catch, показать сообщение об ошибке и попытаться корректно завершить работу приложения ..

1
ответ дан 5 December 2019 в 07:36
поделиться

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

У Фила Хаака есть запись в блоге именно на эту тему.

1
ответ дан 5 December 2019 в 07:36
поделиться

Другими словами, если бы вы писали TryFoo, вы бы гарантировали что исключения не могут избежать писать это так?

Нет, я бы не проглатывал исключения в моем методе TryFoo. Foo зависит от TryFoo, а не наоборот. Поскольку вы упомянули общий словарь, в котором есть методы GetValue и TryGetValue, я бы написал свои методы словаря следующим образом:

public bool TryGetValue(T key, out U value)
{
    IList<KeyValue> kvCollection = internalArray[key.GetHashCode() % internalArray.Length];
    for(KeyValue kv in kvCollection)
    {
        if(kv.Key == key)
        {
            value = kv.Value;
            return true;
        }
    }
    value = default(U);
    return false;
}

public U GetValue(T key)
{
    U value;
    if (TryGetValue(key, out value))
    {
        return value;
    }
    throw new KeyNotFoundException(key);
}

Итак, GetValue зависит от TryGetValue и выдает исключение, если TryGetValue возвращает false. Это намного лучше, чем вызвать GetValue из TryGetValue и проглотить полученное исключение.

1
ответ дан 5 December 2019 в 07:36
поделиться

Однажды я присутствовал на замечательном выступлении человека, который сказал, что участвовал в разработке стратегии обработки исключений для BCL. К сожалению, я забыл его имя и не могу найти свои записи.

Он описал стратегию так:

  1. Имена методов должны быть глаголами, описывающими действие, предпринимаемое методом.
  2. Если действие, описанное имя не имеет места по какой-либо причине, и должно быть сгенерировано исключение.
  3. По возможности, должен быть предоставлен способ тестирования и предотвращения предстоящего исключения. Например, вызов File.Open (filename) вызовет исключение, если файл не существует, но вызов File.Exists (filename) сначала позволит вам этого избежать (в большинстве случаев).
  4. Если есть очевидные причины ( например производительность в общем случае) можно добавить дополнительный метод вызовом TryXXX, где XXX - это имя исходного метода. Этот метод должен иметь возможность обрабатывать режим единственного общего отказа и должен возвращать логическое значение, указывающее на успех или неудачу.

Интересным моментом здесь был №4. Я отчетливо помню, как он говорил о режиме единичного отказа в части рекомендаций. Другие сбои по-прежнему должны вызывать исключения.

Между прочим, он также сказал, что команда CLR сообщила ему, что причина того, что исключения .Net работают медленно, заключается в том, что они реализованы поверх SEH. Они также сказали, что нет особой необходимости в их реализации таким образом (кроме целесообразности), и если они когда-либо попадут в топ-10 реальных проблем с производительностью для реальных клиентов, они подумают о повторной реализации их в будь быстрее!

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

Интересным моментом здесь был №4. Я хорошо помню, как он говорил о режиме единичного отказа в части рекомендаций. Другие сбои по-прежнему должны вызывать исключения.

Между прочим, он также сказал, что команда CLR сообщила ему, что причина того, что исключения .Net работают медленно, заключается в том, что они реализованы поверх SEH. Они также сказали, что нет особой необходимости в их реализации таким образом (кроме целесообразности), и если они когда-либо попадут в топ-10 реальных проблем с производительностью для реальных клиентов, они подумают о повторной реализации их в будь быстрее!

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

Интересным моментом здесь был №4. Я хорошо помню, как он говорил о режиме единичного отказа в части рекомендаций. Другие сбои по-прежнему должны вызывать исключения.

Между прочим, он также сказал, что команда CLR сообщила ему, что причина того, что исключения .Net работают медленно, заключается в том, что они реализованы поверх SEH. Они также сказали, что нет особой необходимости в их реализации таким образом (кроме целесообразности), и если они когда-либо попадут в топ-10 реальных проблем с производительностью для реальных клиентов, они подумают о повторной реализации их в будь быстрее!

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

Между прочим, он также сказал, что команда CLR сообщила ему, что причина того, что исключения .Net работают медленно, заключается в том, что они реализованы поверх SEH. Они также сказали, что нет особой необходимости в их реализации таким образом (кроме целесообразности), и если они когда-либо попадут в топ-10 реальных проблем с производительностью для реальных клиентов, они подумают о повторной реализации их в будь быстрее!

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

Между прочим, он также сказал, что команда CLR сообщила ему, что причина того, что исключения .Net работают медленно, заключается в том, что они реализованы поверх SEH. Они также сказали, что нет особой необходимости в их реализации таким образом (кроме целесообразности), и если они когда-либо попадут в топ-10 реальных проблем с производительностью для реальных клиентов, они подумают о повторной реализации их в будь быстрее!

0
ответ дан 5 December 2019 в 07:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: