TOC

This article has been localized into Russian by the community.

Дополнительные темы:

Обработка исключений

В каждой программе иногда что-то идет не так. В C# у нас есть хороший компилятор, который поможет нам предотвратить некоторые из наиболее распространенных ошибок. Очевидно, что он не может видеть каждую ошибку, которая может произойти, и в этих случаях .NET framework выдаст исключение, чтобы сообщить нам, что что-то пошло не так. В предыдущей главе, посвященной массивам, я описал, как мы получим исключение, если попытаемся поместить слишком много элементов в массив. Приведем пример:

using System;
using System.Collections;

namespace ConsoleApplication1
{
    class Program
    {
static void Main(string[] args)
{
    int[] numbers = new int[2];

    numbers[0] = 23;
    numbers[1] = 32;
    numbers[2] = 42;

    foreach(int i in numbers)
Console.WriteLine(i);
    Console.ReadLine();
}
    }
}

Ладно, попробуйте запустить этот пример, и вы увидите, о чем я говорю. Вы понимаете, что мы делаем неправильно? Мы определили массив целых чисел с объемом для 2 элементов, но мы пытаемся использовать в нем 3 числа. Очевидно, что это приводит к ошибке, которую вы увидите, если вы попытаетесь запустить этот пример. При запуске в Visual Studio IDE дает нам некоторые варианты для исключения, но, если вы попытаетесь выполнить программу, просто дважды щелкнув исполняемый файл, вы получите неприятную ошибку. Если вы знаете, что может произойти ошибка, вы должны справиться с ней. Здесь используются исключения. Вот немного измененная версия вышеприведенного кода:

int[] numbers = new int[2];
try
{
    numbers[0] = 23;
    numbers[1] = 32;
    numbers[2] = 42;

    foreach(int i in numbers)
Console.WriteLine(i);
}
catch
{
    Console.WriteLine("Something went wrong!");
}
Console.ReadLine();

Позвольте мне представить Вам вашего нового лучшего друга, когда дело доходит до обработки ошибок: попробуйте..try.. catch. Попробуйте запустить программу сейчас, и увидите разницу - вместо того, чтобы Visual Studio/Windows говорит нам, что произошла серьезная проблема, мы получаем, чтобы рассказать нашу собственную историю. Но не было бы хорошо, если бы мы могли сказать, что пошло не так? Не проблема:

catch(Exception ex)
{
    Console.WriteLine("An error occured: " + ex.Message);
}

Как видите, мы кое-что добавили в оператор catch. Теперь мы говорим, какое исключение мы хотим поймать, в этом случае базу всех исключений, Exception. Таким образом, мы получаем некоторую информацию о проблеме, которая вызвала исключение, и, выводя свойство Message, мы получаем понятное описание проблемы.

Как я уже сказал, Exception является наиболее общим типом исключения. Правила обработки исключений говорят нам, что мы всегда должны использовать наименее общий тип исключения, и в этом случае мы действительно знаем точный тип исключения, сгенерированного нашим кодом. Как? Потому что Visual Studio сказала нам, когда мы не справились с этим. Если вы сомневаетесь, документация обычно описывает, какие исключения может выдать метод. Другой способ узнать это - использовать класс Exception, чтобы сообщить нам - измените выходную строку на эту:

Console.WriteLine("An error occured: " + ex.GetType().ToString());

Результатом является, как и ожидалось, IndexOutOfRangeException. Поэтому мы должны обрабатывать это исключение, но ничто не мешает нам обрабатывать более одного исключения. В некоторых ситуациях вы можете захотеть сделать разные вещи, в зависимости от того, какое исключение было выдано. Меняем блок Catch для следующий:

catch(IndexOutOfRangeException ex)
{
    Console.WriteLine("An index was out of range!");
}
catch(Exception ex)
{
    Console.WriteLine("Some sort of error occured: " + ex.Message);
}

Как видите, сначала мы ищем исключение IndexOutOfRangeException. Если бы мы сделали это иначе, блок catch с классом Exception получил бы его, потому что все исключения являются производными от него. Другими словами, сначала следует использовать наиболее конкретные исключения.

Еще одна вещь, вы должны знать об исключений блок finally. Блок finally может быть добавлен в набор блоков catch или использоваться исключительно в зависимости от ваших потребностей. Код в блоке finally всегда выполняется - исключение или не исключение. Это хорошее место, если вам нужно закрыть ссылки на файлы или удалить объекты, которые вам больше не понадобятся. Поскольку наши примеры до сих пор были довольно простыми, мы не нуждались в какой-либо очистке, так как сборщик мусора обрабатывает это. Но так как, скорее всего, столкнетесь с ситуациями, когда вам нужен блок finally, вот расширенная версия нашего примера:

int[] numbers = new int[2];
try
{
    numbers[0] = 23;
    numbers[1] = 32;
    numbers[2] = 42;

    foreach(int i in numbers)
Console.WriteLine(i);
}
catch(IndexOutOfRangeException ex)
{
    Console.WriteLine("An index was out of range!");
}
catch(Exception ex)
{
    Console.WriteLine("Some sort of error occured: " + ex.Message);
}
finally
{
    Console.WriteLine("It's the end of our try block. Time to clean up!");
}
Console.ReadLine();

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

Другая важная часть, которую вы должны знать об исключениях, - это то, как они влияют на метод, в котором происходят исключения. Не все необработанные исключения являются фатальными для приложения, но когда они не выполняются, не следует ожидать выполнения оставшегося кода метода. С другой стороны, если вы обработаете исключение, будут выполнены только строки после блока try. В нашем примере цикл, который выводит значения массива, никогда не достигается, потому что блок try переходит прямо к блоку catch / finally после создания исключения. Тем не менее, последняя строка, где мы читаем из консоли, чтобы предотвратить приложение от выхода немедленно, достигается. Вы всегда должны иметь это в виду при построении блоков try.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!