2011-06-08 162 views
8

我正在使用异步CTP编写IO沉重的控制台应用程序。但我遇到异常问题。使用void处理异步异常

public static void Main() 
{ 
    while (true) { 
    try{ 
     myobj.DoSomething(null); 
    } 
    catch(Exception){} 
    Console.Write("done"); 
    //... 
    } 
} 

//... 
public async void DoSomething(string p) 
{ 
    if (p==null) throw new InvalidOperationException(); 
    else await SomeAsyncMethod(); 
} 

并执行以下操作:“完成”被写入到控制台,然后我得到的调试异常,然后我按继续我的程序中存在
什么给?

回答

9

当您致电DoSomething()它基本上创建一个Task在引擎盖下,并开始Task。由于您有void签名,因此没有Task对象发回信号或您可能已被阻止,因此执行直接完成。与此同时,任务会抛出一个无人问津的异常,我怀疑这就是程序终止的原因。

我想你想的行为更像是这样的:

public static void Main() 
{ 
    while (true) { 
    var t = myobj.DoSomething(null); 
    t.Wait(); 
    if(t.HasException) { 
     break; 
    } 
    } 
    Console.Write("done"); 
    //... 
    } 
} 

//... 
public async Task DoSomething(string p) 
{ 
    if (p==null) throw new InvalidOperationException(); 
    else await SomeAsyncMethod(); 
} 

这将在每个DoSomething阻塞,直到它完成,并退出循环,如果DoSomething扔。当然,那么你真的没有做任何异步。但是从伪代码,我不能完全知道你想异步发生什么。

主要外购:对异步方法使用void意味着您无法获得异常,除非您使用异步方法。作为一个同步调用,它基本上只是安排工作,结果消失在以太网中。

+0

我不能调用t.Wait(),因为它阻塞了主控制台线程,所以我不能输入任何东西,所以SomeAsyncMethod永远不会完成(对于我的用法见:http://stackoverflow.com/questions/6145246/how-to-write-c-5-async) – TDaver 2011-06-08 20:14:54

+0

但我想通了!我不会等待任务,将它们放入列表中,并且在每次IO操作(当它们可以抛出异常时)之后,我检查列表是否有任何任务出错! – TDaver 2011-06-08 20:56:58

+1

是的,通常最好启动所有的任务,将它们收集到一个列表中,然后将其收集到一个TaskEx.WhenAll(listOfTasks).Wait()当你想收集所有的工作 – 2011-06-08 23:48:54

11

如果你给你的控制台应用程序异步兼容的情况下(例如,AsyncContextdocssource)从我AsyncEx库),那么你就可以赶上传播完成了这方面的异常,甚至从async void方法:

public static void Main() 
{ 
    try 
    { 
    AsyncContext.Run(() => myobj.DoSomething(null)); 
    } 
    catch (Exception ex) 
    { 
    Console.Error.WriteLine(ex.Message); 
    } 
    Console.Write("done"); 
} 

public async void DoSomething(string p) 
{ 
    if (p==null) throw new InvalidOperationException(); 
    else await SomeAsyncMethod(); 
} 
+4

你已经恢复了原力平衡。谢谢! – 2014-04-23 17:36:32