Procedimiento para controlar excepciones en una consulta PLINQHow to: Handle Exceptions in a PLINQ Query

El primer ejemplo de este tema muestra cómo controlar la clase System.AggregateException que se puede iniciar desde una consulta PLINQ cuando se ejecuta.The first example in this topic shows how to handle the System.AggregateException that can be thrown from a PLINQ query when it executes. El segundo ejemplo muestra cómo colocar bloques try-catch dentro de los delegados, lo más cerca posible de donde se producirá la excepción.The second example shows how to put try-catch blocks within delegates, as close as possible to where the exception will be thrown. De este modo, se pueden detectar en cuanto se producen y posiblemente continuar con la ejecución de la consulta.In this way, you can catch them as soon as they occur and possibly continue query execution. Cuando las excepciones pueden propagarse de nuevo al subproceso de unión, es posible que una consulta continúe procesando algunos elementos después de que se haya producido la excepción.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.

En algunos casos, cuando PLINQ vuelve a realizar la ejecución por secuencias y cuando se produce una excepción, esta puede propagarse directamente y no ajustarse en una excepción 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. Además, las excepciones ThreadAbortException siempre se propagan directamente.Also, ThreadAbortExceptions are always propagated directly.

Nota

Cuando está habilitada la opción "Solo mi código", Visual Studio se interrumpe en la línea que produce la excepción y muestra el mensaje de error "Excepción no controlada por el código de usuario".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." Este error es benigno.This error is benign. Puede presionar F5 para continuar y ver el comportamiento de control de excepciones que se muestra en estos ejemplos.You can press F5 to continue from it, and see the exception-handling behavior that is demonstrated in the examples below. Para evitar que Visual Studio se interrumpa con el primer error, desactive la casilla "Solo mi código" en Herramientas, Opciones, Depurar, General.To prevent Visual Studio from breaking on the first error, just uncheck the "Just My Code" checkbox under Tools, Options, Debugging, General.

La finalidad de este ejemplo es mostrar el uso, y puede que su ejecución no sea tan rápida como la de la consulta LINQ to Objects secuencial equivalente.This example is intended to demonstrate usage, and might not run faster than the equivalent sequential LINQ to Objects query. Para más información sobre la velocidad, vea Introducción a la velocidad en PLINQ.For more information about speedup, see Understanding Speedup in PLINQ.

EjemploExample

Este ejemplo muestra cómo colocar los bloques try-catch alrededor del código que ejecuta la consulta para detectar cualquier excepción System.AggregateException que se produzca.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

En este ejemplo, la consulta no puede continuar después de que se produce la excepción.In this example, the query cannot continue after the exception is thrown. En el momento en que el código de la aplicación detecta la excepción, PLINQ ya ha detenido la consulta en todos los subprocesos.By the time your application code catches the exception, PLINQ has already stopped the query on all threads.

EjemploExample

En el ejemplo siguiente se muestra cómo colocar un bloque try-catch en un delegado para que sea posible detectar una excepción y continuar con la ejecución de la consulta.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

Compilar el códigoCompiling the Code

  • Para compilar y ejecutar estos ejemplos, cópielos en el ejemplo de datos de PLINQ y llame al método desde Main.To compile and run these examples, copy them into the PLINQ Data Sample example and call the method from Main.

Programación sólidaRobust Programming

No se detecta ninguna excepción a menos que sepa cómo controlarla para que no se dañe el estado del programa.Do not catch an exception unless you know how to handle it so that you do not corrupt the state of your program.

Vea tambiénSee also