Практическое руководство. Обработка исключений в выражениях запросов (Руководство по программированию на C#)

В контексте выражения запроса можно вызывать любой метод. Однако не рекомендуется вызывать в выражении запроса методы, которые могут привести к возникновению побочных эффектов, таких как изменение содержимого источника данных или создание исключения. В этом примере показано, как избежать создания исключений при вызове методов в выражениях запросов без нарушения общих правил .NET Framework относительно обработки исключений. Эти правила гласят, что можно перехватывать определенные исключения, если известно, по какой причине они будут созданы в данном контексте. Дополнительные сведения см. в разделе Лучшие методики обработки исключений.

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

Пример

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

class ExceptionsOutsideQuery
{
    static void Main()
    {
        // DO THIS with a datasource that might 
        // throw an exception. It is easier to deal with 
        // outside of the query expression.
        IEnumerable<int> dataSource;
        try
        {
            dataSource = GetData();
        }
        catch (InvalidOperationException)
        {
            // Handle (or don't handle) the exception  
            // in the way that is appropriate for your application.
            Console.WriteLine("Invalid operation");
            goto Exit;
        }

        // If we get here, it is safe to proceed. 
        var query = from i in dataSource
                    select i * i;

        foreach (var i in query)
            Console.WriteLine(i.ToString());

        //Keep the console window open in debug mode
        Exit:
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }

    // A data source that is very likely to throw an exception! 
    static IEnumerable<int> GetData()
    {
        throw new InvalidOperationException();
    }
}

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

Обратите внимание, что блок try заключает в себя цикл foreach, а не сам запрос. Причина заключается в том, что цикл foreach — это точка, в которой запрос фактически выполняется. Дополнительные сведения см. в разделе Введение в запросы LINQ (C#).

class QueryThatThrows
{
    static void Main()
    {
        // Data source. 
        string[] files = { "fileA.txt", "fileB.txt", "fileC.txt" };

        // Demonstration query that throws. 
        var exceptionDemoQuery =
            from file in files
            let n = SomeMethodThatMightThrow(file)
            select n;

        // Runtime exceptions are thrown when query is executed. 
        // Therefore they must be handled in the foreach loop. 
        try
        {
            foreach (var item in exceptionDemoQuery)
            {
                Console.WriteLine("Processing {0}", item);
            }
        }

        // Catch whatever exception you expect to raise 
        // and/or do any necessary cleanup in a finally block 
        catch (InvalidOperationException e)
        {
            Console.WriteLine(e.Message);
        }

        //Keep the console window open in debug mode
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }

    // Not very useful as a general purpose method. 
    static string SomeMethodThatMightThrow(string s)
    {
        if (s[4] == 'C')
            throw new InvalidOperationException();
        return @"C:\newFolder\" + s;
    }
}
/* Output:
    Processing C:\newFolder\fileA.txt
    Processing C:\newFolder\fileB.txt
    Operation is not valid due to the current state of the object.
 */

Компиляция кода

  • Создайте проект Visual Studio, предназначенный для платформы .NET Framework версии 3.5. По умолчанию в проекте имеются ссылка на файл System.Core.dll и директива using (C#) для пространства имен System.Linq.

  • Скопируйте код в созданный проект.

  • Нажмите клавишу F5, чтобы скомпилировать и выполнить программу.

Нажмите любую клавишу для выхода из окна консоли.

См. также

Основные понятия

Выражения запросов LINQ (Руководство по программированию на C#)