为什么异常没有被抓住?

时间:2017-02-01 12:17:11

标签: c# .net exception-handling async-await

我认为我的理解中缺少一些东西。如果我在Console.WriteLine完成的捕获中放置一个断点,它就不会停止。

private static void Main(string[] args)
{
    Process(async () => await ClientMethod()).Invoke();
    Console.Read();
}

public static async Task ClientMethod()
{
    throw new Exception("Test");
}

public static Action Process(Action functor)
{
    return () =>
    {
        try
        {
            functor();
        }
        catch (Exception)
        {
            // Handle exceptions ?
            Console.WriteLine("In the catch");
            throw;
        }
    };
}

但是如果我将代码更改为此代码,则通过删除异步行为,会触发断点:

private static void Main(string[] args)
{
    Process(() => ClientMethod()).Invoke();
    Console.Read();
}

public static void ClientMethod()
{
    throw new Exception("Test");
}

为什么在第一种情况下没有发现异常?我怎么能抓住它?

编辑:我将代码更改为此内容但仍然相同:

private static void Main(string[] args)
{
    var res = Process(async () => await ClientMethod()).Invoke();
    Console.Read();
}

public static async Task<string> ClientMethod()
{
    throw new Exception("Test");
}

public static Func<T> Process<T>(Func<T> functor)
{
    return () =>
    {
        try
        {
            return functor();
        }
        catch (Exception)
        {
            // Handle exceptions ?
            Console.WriteLine("In the catch");
            throw;
        }
    };
}

2 个答案:

答案 0 :(得分:3)

因为正在调用进程中的操作async void

引用:来自Async/Await - Best Practices in Asynchronous Programming

  

Async void方法具有不同的错误处理语义。当一个   异常被抛出async Taskasync Task<T>方法   捕获异常并将其放在Task对象上。用async void   方法,没有Task对象,所以抛出任何异常   异步void方法将直接引发   异步void方法时处于活动状态的SynchronizationContext   启动。

答案 1 :(得分:1)

第一个代码的问题是Action导致创建async void方法。您应该avoid async void有几个原因 - 其中一个原因是异常处理很奇怪(异常不会以任何合理的方式从async void方法传播)。

你的第二个代码很奇怪。如果您记得TTask<string>,您可以更清楚地看到正在发生的事情。所以,你的包装器委托只会返回一个Task<string>;它不会遵守它的例外情况。 To observe exceptions from a task-returning method, you should await the task it returnstry块中的代码不是await任务 - 它只是直接返回它。

解决方案是回到第一个例子。您要做的是将Action委托类型更改为其异步等效项which is Func<Task>。从这里开始,解决方案更自然地流动:

public static Func<Task> Process(Func<Task> functor)
{
  return async () =>
  {
    try
    {
      await functor();
    }
    catch (Exception)
    {
      Console.WriteLine("In the catch");
      throw;
    }
  };
}

用法:

await Process(async () => await ClientMethod()).Invoke();

public static async Task ClientMethod()
{
  throw new Exception("Test");
}
相关问题