C# 使用void进行异步异常处理

C# 使用void进行异步异常处理,c#,asynchronous,exception-handling,async-await,c#-5.0,C#,Asynchronous,Exception Handling,Async Await,C# 5.0,我正在使用Async CTP编写一个IO密集型控制台应用程序。但我有一些例外的问题 public static void Main() { while (true) { try{ myobj.DoSomething(null); } catch(Exception){} Console.Write("done"); //... } } //... public async void DoSomething(stri

我正在使用Async CTP编写一个IO密集型控制台应用程序。但我有一些例外的问题

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();
}
然后发生以下情况:“完成”写入控制台,然后我在调试器中获得异常,然后我按continue我的程序存在
给出了什么?

当您调用
DoSomething()
时,它基本上会在引擎盖下创建一个
任务
,并启动该
任务
。因为您有一个
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
意味着您失去了获取异常的能力,除非您等待该异步方法。作为同步调用,它基本上只是安排工作,结果消失在以太中。

如果您给控制台应用程序一个异步兼容的上下文(例如,我的AsyncEx库中的
AsyncContext
(,),那么您可以捕获从该上下文中传播的异常,即使是从
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();
}

我无法调用t.Wait(),因为它会阻塞主控制台线程,因此我无法输入任何其他内容,因此SomeAsyncMethod将永远不会完成(对于我的用法,请参见:),但我已经解决了!我不等待我的任务,我把它们放到一个列表中,在每次IO操作之后(当它们可以抛出异常时),如果有任何任务出现故障,我会检查列表!是的,通常最好是启动所有任务,将它们收集到一个列表中,然后发送到TaskEx.WhenAll(listOfTasks).Wait()当你想收集所有工作时,我认为你的代码中的
t.HasException
永远不会返回
true
,因为
Wait()
如果任务中的代码引发异常,则引发聚合异常。您已恢复原力的平衡。非常感谢。为什么不改为使用公共异步任务DoSomething(字符串p)(并等待它)?