方法 : クエリ式の例外を処理する (C# プログラミング ガイド)

更新 : 2007 年 11 月

クエリ式のコンテキストで任意のメソッドを呼び出すことができます。ただし、データ ソースの内容が変更されたり例外がスローされたりする副作用が発生する可能性のあるメソッドを、クエリ式で呼び出すことは避けることをお勧めします。ここでは、クエリ式でメソッドを呼び出すときに、例外の処理に関する一般的な .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 クエリの概要」を参照してください。

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 claanup 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.
 */

コードのコンパイル方法

  • .NET Framework Version 3.5 を対象とする Visual Studio プロジェクトを作成します。既定では、プロジェクトには System.Core.dll への参照と System.Linq 名前空間に対する using ディレクティブが含まれます。

  • コードをプロジェクト内にコピーします。

  • F5 キーを押して、プログラムをコンパイルおよび実行します。

任意のキーを押して、コンソール ウィンドウを終了します。

参照

概念

LINQ クエリ式 (C# プログラミング ガイド)