使用void进行异步异常处理

本文关键字:异步 异常处理 void 使用 | 更新日期: 2023-09-27 17:58:37

我正在使用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();
}

发生以下情况:"done"被写入控制台,然后我在调试器中得到异常,然后我按continue我的程序存在
什么东西?

使用void进行异步异常处理

如果您为控制台应用程序提供异步兼容上下文(例如,来自我的AsyncEx库的AsyncContext(docs,source)),则您可以捕获超出该上下文的异常,甚至可以从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();
}

当您调用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意味着你失去了获得异常的能力,除非你是await在使用该异步方法。作为一个同步调用,它基本上只是安排工作,结果消失在以太中。