Ani*_*aul 52 .net c# task task-parallel-library
请看下面的代码 -
static void Main(string[] args)
{
// Get the task.
var task = Task.Factory.StartNew<int>(() => { return div(32, 0); });
// For error handling.
task.ContinueWith(t => { Console.WriteLine(t.Exception.Message); },
TaskContinuationOptions.OnlyOnFaulted);
// If it succeeded.
task.ContinueWith(t => { Console.WriteLine(t.Result); },
TaskContinuationOptions.OnlyOnRanToCompletion);
Console.ReadKey();
Console.WriteLine("Hello");
}
private static int div(int x, int y)
{
if (y == 0)
{
throw new ArgumentException("y");
}
return x / y;
}
Run Code Online (Sandbox Code Playgroud)
如果我在发布模式下执行代码,输出为"发生了一个或多个错误",一旦我点击"Enter"键,"Hello"也会显示.如果我在调试模式下运行代码,输出与但是在IDE中调试时,当控件执行该行时,会出现IDE异常消息("用户代码中未处理的异常")
throw new ArgumentException("y");
Run Code Online (Sandbox Code Playgroud)
如果我从那里继续,程序不会崩溃并显示与发布模式相同的输出.这是处理异常的正确方法吗?
nos*_*tio 66
你也许并不需要单独OnlyOnFaulted
和OnlyOnRanToCompletion
处理程序,而你不处理OnlyOnCanceled
.查看此答案以获取更多详细信息
但是在IDE中进行调试时,控件执行该行时会出现IDE异常消息("用户代码中未处理的异常")
您在调试器下看到异常,因为您可能已在Debug/Exceptions选项(Ctrl+ Alt+ E)中启用它.
如果我从那里继续,程序不会崩溃并显示与发布模式相同的输出.这是处理异常的正确方法吗?
抛出但未在Task
操作中处理的异常不会自动重新抛出.相反,它被包装以供将来观察Task.Exception
(类型AggregateException
).您可以访问原始异常Exception.InnerException
:
Exception ex = task.Exception;
if (ex != null && ex.InnerException != null)
ex = ex.InnerException;
Run Code Online (Sandbox Code Playgroud)
要在这种情况下使程序崩溃,您实际上需要在任务操作之外观察异常,例如通过引用Task.Result
:
static void Main(string[] args)
{
// Get the task.
var task = Task.Factory.StartNew<int>(() => { return div(32, 0); });
// For error handling.
task.ContinueWith(t => { Console.WriteLine(t.Exception.Message); },
TaskContinuationOptions.OnlyOnFaulted);
// If it succeeded.
task.ContinueWith(t => { Console.WriteLine(t.Result); },
TaskContinuationOptions.OnlyOnRanToCompletion);
Console.ReadKey();
Console.WriteLine("result: " + task.Result); // will crash here
// you can also check task.Exception
Console.WriteLine("Hello");
}
Run Code Online (Sandbox Code Playgroud)
更多细节:任务和未处理的异常,.NET 4.5中的任务异常处理.
更新以解决评论:这是我将如何在使用.NET 4.0和VS2010的UI应用程序中执行此操作:
void Button_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<int>(() =>
{
return div(32, 0);
}).ContinueWith((t) =>
{
if (t.IsFaulted)
{
// faulted with exception
Exception ex = t.Exception;
while (ex is AggregateException && ex.InnerException != null)
ex = ex.InnerException;
MessageBox.Show("Error: " + ex.Message);
}
else if (t.IsCanceled)
{
// this should not happen
// as you don't pass a CancellationToken into your task
MessageBox.Show("Canclled.");
}
else
{
// completed successfully
MessageBox.Show("Result: " + t.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
Run Code Online (Sandbox Code Playgroud)
只要您定位.NET 4.0并且您希望.NET 4.0行为用于未观察到的异常(即,当任务被垃圾收集时重新抛出),您应该在以下位置显式配置它app.config
:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
</configuration>
Run Code Online (Sandbox Code Playgroud)
请查看此内容以获取更多详
你所拥有的是一个AggregateException
。这是从任务中抛出的,要求您检查内部异常以查找特定的异常。像这样:
task.ContinueWith(t =>
{
if (t.Exception is AggregateException) // is it an AggregateException?
{
var ae = t.Exception as AggregateException;
foreach (var e in ae.InnerExceptions) // loop them and print their messages
{
Console.WriteLine(e.Message); // output is "y" .. because that's what you threw
}
}
},
TaskContinuationOptions.OnlyOnFaulted);
Run Code Online (Sandbox Code Playgroud)
从 .Net 4.5 开始,您可以使用AggregateException.GetBaseException()
返回“此异常的根本原因”。
不过,该文档似乎有点不对劲。它声称返回另一个 AggregateException。不过,我认为您会发现它返回引发的 ArgumentException。
“发生一个或多个错误”来自任务池产生的包装器异常。Console.WriteLine(t.Exception.ToString())
如果需要,可用于打印整个异常。
IDE 可以自动捕获所有异常,无论它们是否被处理。
归档时间: |
|
查看次数: |
54384 次 |
最近记录: |