在查询表达式中处理异常

在查询表达式的上下文中可以调用任何方法。 但是,我们建议避免在查询表达式中调用任何会产生副作用(如修改数据源内容或引发异常)的方法。 此示例演示在查询表达式中调用方法时如何避免引发异常,而不违反有关异常处理的常规 .NET 指南。 这些指南阐明,当你理解在给定上下文中为何会引发异常时,捕获到该特定异常是可以接受的。 有关详细信息,请参阅异常的最佳做法

最后的示例演示了在执行查询期间必须引发异常时,该如何处理这种情况。

示例 1

以下示例演示如何将异常处理代码移到查询表达式外。 只有当方法不取决于查询的任何本地变量时,才可以执行此操作。

// A data source that is very likely to throw an exception!
IEnumerable<int> GetData() => throw new InvalidOperationException();

// DO THIS with a datasource that might
// throw an exception. It is easier to deal with
// outside of the query expression.
IEnumerable<int>? dataSource = null;
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");
}

if (dataSource is not null)
{
    // 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());
    }
}

示例 2

在某些情况下,针对由查询内部引发的异常的最佳措施可能是立即停止执行查询。 下面的示例演示如何处理可能在查询正文内部引发的异常。 假定 SomeMethodThatMightThrow 可能导致要求停止执行查询的异常。

请注意,try 块封装 foreach 循环,且不对自身进行查询。 这是由于 foreach 循环正是实际执行查询时的点。 有关详细信息,请参阅 LINQ 查询简介

// Not very useful as a general purpose method.
string SomeMethodThatMightThrow(string s) =>
    s[4] == 'C' ?
        throw new InvalidOperationException() :
        @"C:\newFolder\" + s;

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

// The runtime exception will only be thrown when the 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);
}

/* Output:
    Processing C:\newFolder\fileA.txt
    Processing C:\newFolder\fileB.txt
    Operation is not valid due to the current state of the object.
 */

请参阅