處理查詢運算式中的例外狀況Handle exceptions in query expressions

您可在查詢運算式的內容中呼叫任何方法。It's possible to call any method in the context of a query expression. 不過,我們建議您避免在查詢運算式中呼叫任何方法,因為它會產生副作用,例如修改資料來源的內容或擲回例外狀況。However, we recommend that you avoid calling any method in a query expression that can create a side effect such as modifying the contents of the data source or throwing an exception. 此範例顯示如何避免在查詢運算式中呼叫方法時引發例外狀況,卻不違反處理例外狀況的一般 .NET 方針。This example shows how to avoid raising exceptions when you call methods in a query expression without violating the general .NET guidelines on exception handling. 這些方針指出,當您了解為何在指定內容中擲回時,可以接受攔截特定的例外狀況。Those guidelines state that it's acceptable to catch a specific exception when you understand why it's thrown in a given context. 如需詳細資訊,請參閱例外狀況的最佳做法For more information, see Best Practices for Exceptions.

最後一個範例顯示如何處理這種當您在查詢執行期間必須擲回例外狀況的情況。The final example shows how to handle those cases when you must throw an exception during execution of a query.

範例Example

下例示範如何將例外狀況處理程式碼移到查詢運算式之外。The following example shows how to move exception handling code outside a query expression. 只有當方法不依賴任何查詢區域變數時才可以。This is only possible when the method does not depend on any variables local to the query.

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

範例Example

在某些情況下,對從查詢中擲回的例外狀況的最佳回應,可能是立即停止執行查詢。In some cases, the best response to an exception that is thrown from within a query might be to stop the query execution immediately. 下例示範如何處理可能從查詢主體內擲回的例外狀況。The following example shows how to handle exceptions that might be thrown from inside a query body. 假設 SomeMethodThatMightThrow 可能造成需要停止執行查詢的例外狀況。Assume that SomeMethodThatMightThrow can potentially cause an exception that requires the query execution to stop.

請注意,try 區塊會括住 foreach 迴圈,不是括住查詢本身。Note that the try block encloses the foreach loop, and not the query itself. 這是因為 foreach 迴圈是查詢實際執行的點。This is because the foreach loop is the point at which the query is actually executed. 如需詳細資訊,請參閱 LINQ 查詢簡介For more information, see Introduction to LINQ queries.

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 {item}");
            }
        }

        // Catch whatever exception you expect to raise
        // and/or do any necessary cleanup 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.
 */

另請參閱See also