Как узнать, может ли какой-то метод вызвать исключение
Я новичок в разработке для Windows 8 и C#, но у меня есть определенный опыт программирования на Java.
Итак, когда я пытаюсь сделать некоторый синтаксический анализатор Json (например) на java, я не могу сделать это без использования блока try-catch, и таким образом я могу обработать исключение, но когда я пытаюсь сделать то же самое в c# (Windows 8), и я не использую блок try - catch, он тоже работает так:
if (json != null)
{
JObject jObject = JObject.Parse(json);
JArray jArrayUsers = (JArray)jObject["users"];
foreach (JObject obj in jArrayUsers)
{
ListViewMainViewModel user = new ListViewMainViewModel(
(String)obj["email"],
(String)obj["token"],
(String)obj["institution"],
(String)obj["uuidInstitution"]);
usersList.Add(user);
}
return usersList;
}
}
Как я знаю, правильный способ-поймать JsonReaderException, но Visual Studio никогда не предупреждал меня об этом. Я хотел бы знать, есть ли простой способ узнать, если какой-то метод выдает исключение, например, на java с помощью eclipse (это обязательная реализация try-catch block или код не компилируется)
4 ответов
для этого вам придется обратиться к документации. В C# не хватает throws
ключевое слово.
термин для того, что вы ищете, это проверенные исключения, и больше информации можно найти в C# FAQ.
в C# вы отвечаете за обработку исключений - что IMHO является лучшим способом сделать это, чем реализация Java. По сути, исключение должно быть, ну исключительных, то есть: это не то, что вы должны всегда ожидать.
рассмотрим этот странный (пока, общий) анти-шаблон:
try {
} catch (Exception ex) { /* Handler goes here */ }
что это значит? Вы действительно собираетесь обрабатывать каждое исключение, которое проходит через здесь? Даже такие вещи, как OutOfMemoryException
s? Это безумие. Единственное, к чему приведет такой шаблон, - это подавление законных исключений, которые действительно должно чтобы сбить приложение - это довольно похоже на подход Java.
думать Exception
как флаг для программиста, который говорит: "Эй, среда только что вошла в невозможное состояние". Например, если я попытаюсь разделить на ноль, и система бросит DivideByZeroException
, тогда правильно, система должна предупредить вас к этому, потому что это неудача - система не может просто "понять, что это выход", - и если вы просто подавляете проблему, как это действительно помогает? В конце концов, это контрпродуктивно, поскольку все, что вы делаете, - это маскировка того, что на самом деле является невозможным состоянием приложения. Если вы делаете это много в своем приложении, то в конечном итоге он просто превращается в осадок токсичной неправильности. Фу!
исключения также занимают много экранной недвижимости. Иногда мне хочется, чтобы они это сделали. сделайте try/catch/finally
блоки немного более обтекаемые, но потом я вспоминаю, что это побудило бы людей использовать их больше, поэтому я каюсь в этой позиции довольно быстро.
исключения-полезные уведомления программиста к программисту, говорящие, что то, что вы делаете, не имеет смысла. Очевидно, мы никогда не должны передавать необработанные исключения пользователю, потому что они не будут знать, что с ними делать. В то же время вы не хотите пытаться обрабатывать каждое исключение на лице земля, потому что "обработка" в этом смысле обычно превращается в "подавление", что намного хуже, чем просто позволить приложению потерпеть неудачу (изящно).
C#, как уже упоминалось, не имеет проверенных исключений, и слава богу.
идея проверенных исключений звучит отлично, но поговорите с любым, кто вынужден использовать их языком или средой выполнения, и они скажут, что есть три большие проблемы с проверенными исключениями:
- они навязывают свою волю использующей кодер. проверенные исключения, по их определению, должны обрабатываться до того, как они будут выброшены из во время выполнения. Среда выполнения фактически говорит кодеру:"вы должны знать, что делать, когда я бросаю это, поэтому сделайте это". Во-первых, подумайте об этом, вы сказали ожидал то, что происходит в исключительных случаи по самому своему определению. Во-вторых, вы должны как-то с этим справиться. Ну, это все хорошо, когда у вас есть возможность решить проблему, на которую указывает исключение. К сожалению, у нас не всегда есть эта способность, и мы не всегда хотим это делать все, что нужно. Если я пишу простой апплет формы, который выполняет преобразование данных, и я просто хочу, чтобы мое приложение умерло огненной смертью, если есть какие-либо проблемы, я не могу просто ничего не поймать; я должен подняться на все возможные стеки вызовов каждого метода, который может бросить что-то и добавить то, что он может бросить в предложение throws (или быть очень ленивым и поставить предложение "исключение бросков" на каждый метод моей кодовой базы). Аналогично, если мое приложение построено так, что я не могу выбросьте конкретное исключение, возможно, потому, что я реализую интерфейс вне моего контроля, который не указывает его как потенциальный throwable, тогда мои единственные варианты-полностью проглотить его и вернуть возможно недопустимый результат моим абонентам или обернуть исключение в непроверенный тип throwable как RuntimeException и выбросить его таким образом (игнорируя весь проверенный механизм исключения, который, конечно, не рекомендуется).
- они нарушают твердое тело, особенно принцип "открыто-закрыто". внесите изменение, которое добавляет проверенное исключение в ваш код, и если вы не можете обработать указанное исключение, все использования вашего метода должны либо обработать его, либо пометить себя как выбрасывание исключения. Обычаи, которые rethrow должны обрабатываться их собственными абонентами или они должны быть отмечены как бросающие то же исключение. Сделав изменение столь же хирургическим, как вызов альтернативного метода в определенной строке кода, теперь вам нужно отследить все возможные вызовы стеки и внесите другие изменения в код, который работал нормально, просто чтобы сказать им, что ваш код может создать исключение.
-
они создают дырявые абстракции по определению. вызывающий объект, использующий метод с предложением "throws", должен, по сути, знать эти детали реализации о своей зависимости. Затем, если он не желает или не может справиться с этими ошибками, он должен сообщить об этих ошибках своим собственным потребителям. Проблема усугубляется, когда метод является частью реализации интерфейса; чтобы объект бросил его, интерфейс должен указать его как throwable, даже если не все реализации бросают это исключение.
Java смягчает это, имея многоуровневую иерархию классов исключений; все исключения, связанные с вводом-выводом, являются (должны быть) IOExceptions, например, и интерфейс с методами, которые имеют цели, связанные с IO, может указать, что IOException может быть брошено, освобождая его от ответственности за укажите каждое конкретное дочернее исключение IOException. Однако это вызывает почти столько же проблем, сколько и решает; есть десятки IOExceptions, которые могут иметь очень разные причины и решения. Таким образом, вы должны опросить каждое исключение IOException, которое вы ловите во время выполнения, чтобы получить его правда type (и вы получаете мало или нет помощи в определении конкретных, которые могут быть брошены), чтобы определить, является ли это то, что вы можете обрабатывать автоматически, и как.
EDIT: еще одна большая проблема:
-
они предполагают, что try-catch-единственный способ справиться с возможной ситуацией исключения. предположим, вы находитесь в C# в альтернативной вселенной, где C# имеет проверенные исключения в стиле Java. Вы хотите, чтобы ваш метод открывал и читал файл с именем файла, переданным в него вызывающим. Как хороший маленький кодер, вы сначала проверяете, что файл существует в предложении guard, используя .Существует (который никогда не будет выдавать исключение; чтобы вернуть true, путь должен быть действительным, файл, указанный в пути, должен существовать, и исполняющая учетная запись пользователя должна иметь по крайней мере доступ для чтения к папке и файлу). Если Файл.Exists возвращает false, ваш метод просто не возвращает данных, и ваши абоненты знают, что делать (скажем, этот метод открывает файл, содержащий необязательные Данные конфигурации, и если он не существует, пуст или поврежден, ваша программа генерирует и использует конфигурация по умолчанию.)
Если файл существует, вы затем вызовите файл.Открыть. Ну,.Открыть может выдавать девять различных типов исключений. Но ни один из них, скорее всего, не произойдет, потому что вы уже проверили с помощью файла.Существует, что файл может быть открыт только для чтения Пользователем при запуске программы. Однако проверенному механизму исключений все равно; метод, который вы используете, указывает, что он может вызывать эти исключения, и поэтому вы должны либо обрабатывать их, либо указывать что ваш собственный метод может бросить их,даже если вы можете принять все меры предосторожности, чтобы предотвратить его. Ответом было бы проглотить их и вернуть null (или забыть предложение guard и просто поймать и обработать файл.Исключения Open), но это шаблон, которого вы пытались избежать с помощью предложения guard в первую очередь.
ничто из этого даже не учитывает потенциал зла. Разработчик может, например, поймать и оставить непроверенный исключение как проверенное (например, улавливание NullPointerException и выбрасывание IOException), и теперь вам нужно поймать (или указать, что ваш метод выбрасывает) исключение, которое даже не является хорошим представлением того, что не так.
Что касается того, что использовать вместо C#, лучше всего использовать комментарии к XML-документации сообщить непосредственному вызывающему абоненту с помощью вашего метода, что из него потенциально может быть вызвано исключение. XML-doc является эквивалентом .NET к комментариям JavaDoc и используется примерно так же, но синтаксис отличается (три косых черты, за которыми следуют комментарии, окруженные системой XML-тегов). The тег для исключения достаточно легко определить. Чтобы эффективно документировать вашу кодовую базу, я рекомендую GhostDoc. Однако он будет генерировать комментарии исключений только для исключений, явно вызванных из документируемого метода, и вам придется заполнить некоторые пробелы.
Я не разработчик java, но из ответов здесь кажется, что реализация Java является бременем для клиентов этих методов. Тем не менее, C# упустил возможность (Java-как или иначе) сообщить вызывающему тип исключительных результатов, которые могут произойти, как автор разработчиком метода, что позволяет мне вызывающему абоненту обрабатывать его соответствующим образом.
поскольку эта конструкция не встроена в язык, я бы предложил разработчикам библиотек, чтобы вы примите класс-оболочку и используйте его в качестве возвращаемого типа для любых методов, которые могут пойти не так. Используя этот класс в качестве возвращаемого типа вместо исключений, клиенты могут рассуждать о том, чего ожидать при вызове метода, поскольку он четко определен в сигнатуре метода. Кроме того, использование оболочки позволит методу рассказать клиенту, почему что-то пошло не так, как это делают исключения.
больше на эту тему здесь: http://enterprisecraftsmanship.com/2015/03/20/functional-c-handling-failures-input-errors/