我应该这样做吗?
int x = 0;
Task<int> calc = Task.Factory.StartNew (() => 7 / x);
try
{
Console.WriteLine (calc.Result);
}
catch (AggregateException aex)
{
Console.Write (aex.InnerException.Message); // Attempted to divide by 0
}
还是这个?
int x = 0;
try
{
Task<int> calc = Task.Factory.StartNew (() => 7 / x);
Console.WriteLine (calc.Result);
}
catch (AggregateException aex)
{
Console.Write (aex.InnerException.Message); // Attempted to divide by 0
}
如果任务立即开始,然后在我们进入try catch块之前,我们就不会抓住它......!
答案 0 :(得分:1)
使用Task
的一个要点是你大多不必担心这样的事情。
正如您所注意到的,第一个样本有两种可能的事件顺序:
StartNew()
。Result
getter。任务尚未完成,因此调用阻塞。DivideByZeroException
。Result
抛出AggregateException
。第二种可能性是:
StartNew()
。DivideByZeroException
。Result
getter。任务已经完成,因此调用会立即抛出AggregateException
。如您所见,在两种情况下Result
getter抛出异常,代码执行的顺序无关紧要。
只有StartNew()
可以抛出AggregateException
,你的第二个版本才有意义,但这种情况永远不会发生。
让我再说一遍:TPL负责所有的同步,你不必在此担心。
答案 1 :(得分:0)
任务有一个Exception
属性,用于保存在任务执行期间抛出的异常(如果有的话)。这意味着你可以这样做:
int x = 0;
Task<int> calc = Task.Factory.StartNew(() => 7 / x);
calc.ContinueWith(t => Console.WriteLine ("Got exception of {0}", t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
答案 2 :(得分:0)
您希望在try块中执行尽可能少的代码,因为您包含的内容越多,您将捕获的虚假,不需要的异常。你只想抓住那些你知道他们是良性的。你不想吞下虫子。
因此要么这样做:
var task = ...;
int result;
try { result = task.Result; } //just catch task.Result
...
甚至是这样:
if (task.Exception != null) { /* error */ }
else { /* use task.Result */ }
答案 3 :(得分:0)
在这种情况下,您不需要将其包含在try块中。除非你传递一个null Action来执行,否则Task.Factory.StartNew不会抛出异常。正在运行的操作抛出的任何异常都将传播到任务中,而不是传播到堆栈中。
更一般地说,我认为这些类型的情况的经验法则是异常应该总是进入任务。例如,如果在异步方法中的第一个await之前抛出异常,它也会进入生成的任务,而不是向上传播堆栈。