Этот блог некоторое время был тихим. Я сейчас пишу книгу о локализации. Я и мой партнер также приближаемся к выпуску нашего нового стартапа. Одна из его функций — автоматически перехватывать необработанные исключения и отправлять их в веб-сервис для аналитики. Но чтобы в полной мере воспользоваться этим, вам придется воспользоваться набором лучших методов обработки исключений. Поэтому я собираюсь написать ряд статей об исключениях. Серия закончится выпуском нашего сервиса.
Что такого исключительного за исключением?
Познакомьтесь с Бобом:
Он получил больше денег, чем он может справиться. Следовательно, каждый раз, когда он делает покупки, он просто смахивает эту карточку и платит.
Встретиться с Сэмом
Ему не так повезло, и каждый доллар считается. Это означает, что он не просто смахивает свою кредитную карту и ожидает, что она будет работать. Обычно он заходит в банкомат, чтобы проверить баланс.
Я хочу сказать, что у них обоих был сценарий использования «Оплата товаров кредитной картой». Но так как Боб не ожидает, что карта будет пустой, он просто смахивает эту bling bling карту без предварительной проверки. Сэм, с другой стороны, ожидает, что платеж не удастся. Поэтому он удостоверится в том, что на карте достаточно денег, прежде чем ее украсть.
Теперь представьте, что кто-то взломал карту Бобса, поэтому она пуста. Он пойдет в магазин с этой широкой жирной усмешкой и будет делать покупки, как сумасшедший, как обычно. Но на этот раз его ждет сюрприз: на счету нет денег. Он понимает, что не так, но не почему. Следовательно, он ничего не может с этим поделать. Ему придется пойти домой и попытаться понять, что произошло, а также попытаться предотвратить это в будущем.
И это то, что является исключением.
Пример кода
Если у вас есть файл XML, который поставляется вместе с вашим продуктом, например, список продуктов, вы ожидаете, что он существует. Если этого не произойдет, вы ничего не можете с этим поделать. Следовательно, произошло нечто исключительное.
С другой стороны, если у вас есть файл XML, который содержит кэш самых последних использованных продуктов, вы ожидаете, что этот файл не будет существовать в первый раз. Если это не так, просто создайте его и добавьте продукт, над которым в данный момент работает пользователь.
То, что я говорю, — то, что является исключительным, зависит от варианта использования. В одном случае жизненно важно, чтобы файл существовал, в другом случае вы можете продолжить, просто создав файл.
Исключительными являются случаи, когда вы не можете спасти ситуацию, чтобы приложение продолжало работать, как ожидалось.
Если мы переведем оба случая в код, первое будет выглядеть примерно так:
public IEnumerable<Product> GetProducts() { using (var stream = File.Read(Path.Combine(Environment.CurrentDirectory, "products.xml"))) { var serializer = new XmlSerializer(); return (IEnumerable<Product>)serializer.Deserialize(stream); } }
В приведенном выше примере вы ожидаете, что файл существует. Таким образом, вы не должны пытаться обрабатывать какие-либо исключения в нем (так как на самом деле нет способа воссоздать список продуктов).
Другой пример, с другой стороны, ожидает, что файл не существует. Поэтому мы проверяем, существует ли файл:
public IEnumerable<Product> GetCachedProducts() { var fullPath = Path.Combine(Environment.CurrentDirectory, "ProductCache.xml"); if (!File.Exists(fullPath)) return new Product[0]; using (var stream = File.Read(fullPath)) { var serializer = new XmlSerializer(); return (IEnumerable<Product>)serializer.Deserialize(stream); } }
Когда ловить исключения
Так когда же вы должны ловить исключения?
Когда вы можете заставить метод возвращать то, что от него ожидается.
Давайте использовать приведенные выше примеры снова:
IEnumerable<Product> GetProducts()
Этот метод говорит, что он всегда должен возвращать список продуктов. Если вы можете сделать это, поймав исключение, сделайте это. Если вы не можете, вы не должны ловить исключения в этом.
IEnumerable<Product> GetCachedProducts()
Этот метод немного сложнее. Мы могли бы поймать FileNotFoundException
это и использовать это, чтобы обнаружить, отсутствует ли файл кэша. Это, однако, говорит о том, что мы ожидали, что файл должен существовать, но мы можем спасти ситуацию, обработав исключение. Это неправда. Мы ожидаем, что файл не существует.
Резюме
Исключительные случаи — это то, что вы не можете предвидеть. Это может быть логическая ошибка, совершенная вами (читай: ошибка) или что-то не зависящее от вас (например, ошибки ОС / сети / диска). Это означает, что в большинстве случаев вы не можете обработать эти ошибки, даже если попытаетесь их отловить. Или еще хуже: вы ловите их, не справляетесь с ними и таким образом скрываете ошибку, которую будет намного сложнее найти и решить. Просто не делайте ничего с исключениями, с которыми вы не можете справиться.
Если вы хотите перехватывать исключения для их регистрации, делайте это на верхнем уровне (например, WCF или ASP.NET MVC). Ваш код станет намного менее загроможденным.