方法: PLINQ クエリの例外を処理するHow to: Handle Exceptions in a PLINQ Query

このトピックの最初の例では、PLINQ クエリの実行時にスローされる System.AggregateException の処理方法を示します。The first example in this topic shows how to handle the System.AggregateException that can be thrown from a PLINQ query when it executes. 2 番目の例では、デリゲート内で例外がスローされる場所のできるだけ近くに try-catch ブロックを配置する方法を示します。The second example shows how to put try-catch blocks within delegates, as close as possible to where the exception will be thrown. こうすると、発生の直後に例外をキャッチしてクエリの実行を続行できる可能性があります。In this way, you can catch them as soon as they occur and possibly continue query execution. 連結しているスレッドへ例外が上方向へ通知されると、例外が発生した後も、クエリによって一部の項目の処理が続行される可能性があります。When exceptions are allowed to bubble up back to the joining thread, then it is possible that a query may continue to process some items after the exception is raised.

場合によっては、PLINQ が順次実行に戻り、例外が発生すると、例外が直接反映され、AggregateException にラップされないことがあります。In some cases when PLINQ falls back to sequential execution, and an exception occurs, the exception may be propagated directly, and not wrapped in an AggregateException. また、ThreadAbortException は常に直接反映されます。Also, ThreadAbortExceptions are always propagated directly.

注意

[マイ コードのみ] が有効になっている場合、Visual Studio では、例外をスローする行で処理が中断され、"ユーザー コードで処理されない例外" に関するエラー メッセージが表示されます。When "Just My Code" is enabled, Visual Studio will break on the line that throws the exception and display an error message that says "exception not handled by user code." このエラーは問題にはなりません。This error is benign. F5 キーを押して、処理が中断された箇所から続行し、以下の例に示す例外処理動作を確認できます。You can press F5 to continue from it, and see the exception-handling behavior that is demonstrated in the examples below. Visual Studio による処理が最初のエラーで中断しないようにするには、[ツール] メニューの [オプション]、[デバッグ] 、[全般] の順にクリックし、[マイ コードのみ] チェック ボックスをオフにします。To prevent Visual Studio from breaking on the first error, just uncheck the "Just My Code" checkbox under Tools, Options, Debugging, General.

この例は、使用方法を示すことを意図したものであるため、同等の順次的な LINQ to Objects クエリほど高速ではない可能性があります。This example is intended to demonstrate usage, and might not run faster than the equivalent sequential LINQ to Objects query. 高速化の詳細については、「PLINQ での高速化について」を参照してください。For more information about speedup, see Understanding Speedup in PLINQ.

Example

次の例は、スローされる System.AggregateException をキャッチするクエリを実行するコードの近くに try-catch ブロックを配置する方法を示しています。This example shows how to put the try-catch blocks around the code that executes the query to catch any System.AggregateExceptions that are thrown.

// Paste into PLINQDataSample class.
static void PLINQExceptions_1()
{
    // Using the raw string array here. See PLINQ Data Sample.
    string[] customers = GetCustomersAsStrings().ToArray();


    // First, we must simulate some currupt input.
    customers[54] = "###";

    var parallelQuery = from cust in customers.AsParallel()
                        let fields = cust.Split(',')
                        where fields[3].StartsWith("C") //throw indexoutofrange
                        select new { city = fields[3], thread = Thread.CurrentThread.ManagedThreadId };
    try
    {
        // We use ForAll although it doesn't really improve performance
        // since all output is serialized through the Console.
        parallelQuery.ForAll(e => Console.WriteLine("City: {0}, Thread:{1}", e.city, e.thread));
    }

    // In this design, we stop query processing when the exception occurs.
    catch (AggregateException e)
    {
        foreach (var ex in e.InnerExceptions)
        {
            Console.WriteLine(ex.Message);
            if (ex is IndexOutOfRangeException)
                Console.WriteLine("The data source is corrupt. Query stopped.");
        }
    }
}
' Paste into PLINQDataSample class
Shared Sub PLINQExceptions_1()

    ' Using the raw string array here. See PLINQ Data Sample.
    Dim customers As String() = GetCustomersAsStrings().ToArray()

    ' First, we must simulate some currupt input.
    customers(20) = "###"

    'throws indexoutofrange
    Dim query = From cust In customers.AsParallel() _
        Let fields = cust.Split(","c) _
        Where fields(3).StartsWith("C") _
        Select fields
    Try
        ' We use ForAll although it doesn't really improve performance
        ' since all output is serialized through the Console.
        query.ForAll(Sub(e)
                         Console.WriteLine("City: {0}, Thread:{1}")
                     End Sub)
    Catch e As AggregateException

        ' In this design, we stop query processing when the exception occurs.
        For Each ex In e.InnerExceptions
            Console.WriteLine(ex.Message)
            If TypeOf ex Is IndexOutOfRangeException Then
                Console.WriteLine("The data source is corrupt. Query stopped.")
            End If
        Next
    End Try
End Sub

この例では、例外がスローされた後にクエリを続行することはできません。In this example, the query cannot continue after the exception is thrown. アプリケーション コードが例外をキャッチするまでに、PLINQ はすべてのスレッド上でクエリを停止しています。By the time your application code catches the exception, PLINQ has already stopped the query on all threads.

Example

次の例は、例外をキャッチしてクエリの実行を続行できるようにするため、try-catch ブロックをデリゲートに配置する方法を示しています。The following example shows how to put a try-catch block in a delegate to make it possible to catch an exception and continue with the query execution.

// Paste into PLINQDataSample class.
static void PLINQExceptions_2()
{

    var customers = GetCustomersAsStrings().ToArray();
    // Using the raw string array here.
    // First, we must simulate some currupt input
    customers[54] = "###";

    // Create a delegate with a lambda expression.
    // Assume that in this app, we expect malformed data
    // occasionally and by design we just report it and continue.
    Func<string[], string, bool> isTrue = (f, c) =>
    {
        try
        {
            string s = f[3];
            return s.StartsWith(c);
        }
        catch (IndexOutOfRangeException e)
        {
            Console.WriteLine("Malformed cust: {0}", f);
            return false;
        }
    };

    // Using the raw string array here
    var parallelQuery = from cust in customers.AsParallel()
                        let fields = cust.Split(',')
                        where isTrue(fields, "C") //use a named delegate with a try-catch
                        select new { city = fields[3] };
    try
    {
        // We use ForAll although it doesn't really improve performance
        // since all output must be serialized through the Console.
        parallelQuery.ForAll(e => Console.WriteLine(e.city));
    }

    // IndexOutOfRangeException will not bubble up      
    // because we handle it where it is thrown.
    catch (AggregateException e)
    {
        foreach (var ex in e.InnerExceptions)
            Console.WriteLine(ex.Message);
    }
}
' Paste into PLINQDataSample class
Shared Sub PLINQExceptions_2()

    Dim customers() = GetCustomersAsStrings().ToArray()
    ' Using the raw string array here.
    ' First, we must simulate some currupt input
    customers(20) = "###"

    ' Create a delegate with a lambda expression.
    ' Assume that in this app, we expect malformed data
    ' occasionally and by design we just report it and continue.
    Dim isTrue As Func(Of String(), String, Boolean) = Function(f, c)

                                                           Try

                                                               Dim s As String = f(3)
                                                               Return s.StartsWith(c)

                                                           Catch e As IndexOutOfRangeException

                                                               Console.WriteLine("Malformed cust: {0}", f)
                                                               Return False
                                                           End Try
                                                       End Function

    ' Using the raw string array here
    Dim query = From cust In customers.AsParallel()
                        Let fields = cust.Split(","c)
                        Where isTrue(fields, "C")
                       Select New With {.City = fields(3)}
    Try
        ' We use ForAll although it doesn't really improve performance
        ' since all output must be serialized through the Console.
        query.ForAll(Sub(e) Console.WriteLine(e.city))


        ' IndexOutOfRangeException will not bubble up      
        ' because we handle it where it is thrown.
    Catch e As AggregateException
        For Each ex In e.InnerExceptions
            Console.WriteLine(ex.Message)
        Next
    End Try
End Sub

コードのコンパイルCompiling the Code

  • これらの例をコンパイルして実行するには、これらのコードを PLINQ データのサンプルにコピーして、Main からメソッドを呼び出します。To compile and run these examples, copy them into the PLINQ Data Sample example and call the method from Main.

信頼性の高いプログラミングRobust Programming

プログラムの状態を破損しないようにするため、処理方法がわからない場合は、例外をキャッチしないでください。Do not catch an exception unless you know how to handle it so that you do not corrupt the state of your program.

関連項目See also