Procedure: Uitzonderingen verwerken in een PLINQ-query
In het eerste voorbeeld in dit onderwerp ziet u hoe u de System.AggregateException gegevens kunt verwerken die kunnen worden gegenereerd vanuit een PLINQ-query wanneer deze wordt uitgevoerd. In het tweede voorbeeld ziet u hoe u try-catch-blokken binnen gedelegeerden plaatst, zo dicht mogelijk bij waar de uitzondering wordt gegenereerd. Op deze manier kunt u ze vangen zodra ze plaatsvinden en mogelijk doorgaan met het uitvoeren van query's. Wanneer uitzonderingen zijn toegestaan om terug te bellen naar de samenvoegingsthread, is het mogelijk dat een query bepaalde items blijft verwerken nadat de uitzondering is gegenereerd.
In sommige gevallen wanneer PLINQ terugvalt op sequentiële uitvoering, en er een uitzondering optreedt, kan de uitzondering rechtstreeks worden doorgegeven en niet worden verpakt in een AggregateException. ThreadAbortExceptionOok worden s altijd rechtstreeks doorgegeven.
Notitie
Wanneer Just My Code is ingeschakeld, wordt Visual Studio verbroken op de regel die de uitzondering genereert en wordt er een foutbericht weergegeven met de tekst 'Uitzondering die niet wordt verwerkt door gebruikerscode'. Deze fout is goedaardig. U kunt op F5 drukken om verder te gaan en het gedrag voor uitzonderingsafhandeling te bekijken dat in de onderstaande voorbeelden wordt gedemonstreerd. Als u wilt voorkomen dat Visual Studio de eerste fout veroorzaakt, schakelt u het selectievakje Just My Code uit onder Extra, Opties, Foutopsporing, Algemeen.
Dit voorbeeld is bedoeld om het gebruik te demonstreren en kan mogelijk niet sneller worden uitgevoerd dan de equivalente opeenvolgende LINQ naar objectenquery. Zie Inzicht in snelheid in PLINQ voor meer informatie over versnelling.
Voorbeeld 1
In dit voorbeeld ziet u hoe u de try-catch-blokken rond de code plaatst waarmee de query wordt uitgevoerd om eventuele System.AggregateExceptiongegenereerde s te vangen.
// 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 corrupt 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 corrupt 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 dit voorbeeld kan de query niet doorgaan nadat de uitzondering is gegenereerd. Op het moment dat de toepassingscode de uitzondering onderschept, heeft PLINQ de query al op alle threads gestopt.
Voorbeeld 2
In het volgende voorbeeld ziet u hoe u een try-catch-blok in een gemachtigde plaatst om een uitzondering te ondervangen en door te gaan met de uitvoering van de query.
// Paste into PLINQDataSample class.
static void PLINQExceptions_2()
{
var customers = GetCustomersAsStrings().ToArray();
// Using the raw string array here.
// First, we must simulate some corrupt input
customers[54] = "###";
// Assume that in this app, we expect malformed data
// occasionally and by design we just report it and continue.
static bool IsTrue(string[] f, string c)
{
try
{
string s = f[3];
return s.StartsWith(c);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine($"Malformed cust: {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 corrupt 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
De code compileren
- Als u deze voorbeelden wilt compileren en uitvoeren, kopieert u deze naar het voorbeeld van het PLINQ-gegevensvoorbeeld en roept u de methode aan vanuit Main.
Robuuste programmering
Neem geen uitzondering tenzij u weet hoe u deze moet afhandelen, zodat u de status van uw programma niet beschadigd.