閱讀英文

共用方式為


如何:處理 PLINQ 查詢中的例外狀況

此主題中的第一個範例顯示如何處理當執行 PLINQ 查詢時可從它擲回的 System.AggregateException。 第二個範例顯示如何將 try-catch 區塊放在委派內,且盡可能地接近將擲回例外狀況的位置。 如此一來,您可以在發生例外狀況時立即攔截它們,並可能繼續執行查詢。 當系統允許例外狀況反昇至聯結的執行緒時,查詢可能就可以在引發例外狀況之後,繼續處理某些項目。

在某些 PLINQ 回復為循序執行且發生例外狀況的情況中,例外狀況可能會直接傳播,而不會包裝在 AggregateException 中。 此外,ThreadAbortException 一律會直接傳播。

注意

啟用 [Just My Code] 時,Visual Studio 會在擲回例外狀況的字行上中斷,並顯示錯誤訊息,指出「使用者程式碼未處理例外狀況」。這個錯誤是良性的。 您可以按 F5 鍵繼續,並查看下面範例中示範的例外狀況處理行為。 若要防止 Visual Studio 在遇到第一個錯誤時就中斷,只要取消核取 [工具]、[選項]、[偵錯]、[一般] 下的 [Just My Code] 核取方塊即可。

這個範例是為了示範用法,執行速度可能比不上對應的循序 LINQ to Objects 查詢。 如需加速的詳細資訊,請參閱認識 PLINQ 中的加速

範例 1

此範例會示範如何在執行查詢的程式碼周圍放置 try-catch 區塊,以攔截任何擲回的 System.AggregateException

// 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.");
        }
    }
}

在此範例中,擲回例外狀況之後查詢無法繼續。 應用程式程式碼攔截到例外狀況時,PLINQ 已經停止所有執行緒上的查詢。

範例 2

下列範例會示範如何將 try-catch 區塊放在委派中,以使其可攔截例外狀況並繼續執行查詢。

// 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);
        }
    }
}

編譯程式碼

  • 若要編譯並執行這些範例,請將它們複製到 [PLINQ 資料範] 範例中,並從 Main 呼叫方法。

穩固程式設計

除非您知道如何處理,否則請勿攔截例外狀況,這樣您才不會損毀您的程式狀態。

另請參閱