我正在查询数据库并将结果包装到视图模型中。测试故意错误的连接字符串,当查询在for (object result in query)
执行时抛出异常。根据我的研究(下文),异常应由外部try/catch
块处理,而不添加async
作为lambda的关键字。但是,当我运行没有async
关键字的代码时,不会捕获异常并且程序崩溃。
为什么我的例外没有被处理?
请注意,此处唯一的更改是在async
的lambda表达式中添加Task.Run
。
According to Stephen Cleary's comment on this answer外部try/catch
应该在没有async
的情况下捕获异常。
I have confirmed that "Break When Thrown" is disabled
更新
通过评论,我尝试了Disabling "Just my Code"
它确实允许捕获异常,但它仍然会产生异常行为。
如果您运行非 - 同步示例,而#34; Just My Code"如果禁用,则在返回catch块之前抛出异常15次。
外部try/catch
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Data.Linq;
using System.Data.Linq.Mapping;
namespace ThisQuestion
{
class Program
{
static void Main(string[] args)
{
DoWork();
Console.ReadLine();
}
private async static void DoWork()
{
DataContext _db = new DataContext("badconnectionstring");
Table<Objects> objects = _db.GetTable<Objects>();
IQueryable<object> query =
from o in objects
select o;
try
{
await Task.Run
(() =>
{
foreach (object result in query) ;
});
}
catch (System.Data.SqlClient.SqlException)
{
System.Diagnostics.Debug.WriteLine("SQLError");
}
}
}
[Table(Name="Objects")]
class Objects
{
private string AColumn;
}
}
外部try/catch
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Data.Linq;
using System.Data.Linq.Mapping;
namespace ThisQuestion
{
class Program
{
static void Main(string[] args)
{
DoWork();
Console.ReadLine();
}
private async static void DoWork()
{
DataContext _db = new DataContext("badconnectionstring");
Table<Objects> objects = _db.GetTable<Objects>();
IQueryable<object> query =
from o in objects
select o;
try
{
await Task.Run
(async () =>
{
foreach (object result in query) ;
});
}
catch (System.Data.SqlClient.SqlException)
{
System.Diagnostics.Debug.WriteLine("SQLError");
}
}
}
[Table(Name="Objects")]
class Objects
{
private string AColumn;
}
}
答案 0 :(得分:2)
异常仍未正确处理
我认为这不是正确的陈述。
在两个版本的代码中,您的catch (System.Data.SqlClient.SqlException)
语句都会捕获异常。怎么不&#34;正确&#34;?
您看到差异的唯一原因是调试器的行为方式。在第二个示例中,调试器不会报告异常,因为就其而言,正在处理异常。由异步lambda返回的Task
对象观察到它(注意在这种情况下调用Task.Run(Func<Task>)
重载)。
在第一个代码示例中,Run()
方法正在执行直接Action
lambda。在这种情况下,发生异常的线程中没有Task
对象;只有原始帖子中你调用Task.Run()
的那个。因此,就调试器而言,异常是在该线程中未处理的发生的。
因此,在第一个示例中,通过调试器的规则,异常未处理。当然,它仍然被观察到。 Task
返回的Task.Run()
对象封装了异常,您可以通过等待Task
对象来观察它。
在第二个示例中,通过调试器的规则,处理异常。通过异步lambda返回的Task
对象在它发生的同一个线程中观察到它。调试器没问题,也没有通知你。
但在这两个示例中,代码的基本行为是相同的。您的任务抛出异常,并通过等待Task
返回的Task.Run()
对象在原始线程中捕获(因为在任何一种情况下,异常都传播到该Task
对象,只是通过不同的机制)。
注意:以上内容仅适用于您提供的两个完整代码示例。您在关于&#34; 15例外&#34;等的问题中还有其他讨论,我无法解决,因为没有MCVE可以再现该行为。但假设您在两个完整的代码示例中正确表示了基本问题,则上述内容将适用于您所询问的更广泛的场景。