【问题标题】:AggregateException C# example聚合异常 C# 示例
【发布时间】:2011-07-19 23:56:34
【问题描述】:

我在网上看到了AggregateException 的示例,我正在尝试弄清楚它是如何工作的。我写了一个简单的例子,但是我的代码由于某种原因不起作用。

谁能解释一下问题出在哪里?

public static void Main()
{
    try
    {
        Parallel.For(0, 500000, i =>
        {
            if (i == 10523)
                throw new TimeoutException("i = 10523");
            Console.WriteLine(i + "\n");
        });
    }
    catch (AggregateException exception)
    {
        foreach (Exception ex in exception.InnerExceptions)
        {
            Console.WriteLine(ex.ToString());
        }
    }
}

【问题讨论】:

  • 什么不起作用?你期望发生什么?
  • 用户代码未处理超时异常
  • 您是说您希望异常由 catch 块处理,但您却得到“用户代码未处理超时异常”,对吗?如果是这种情况,Yahia 答案和 cmets 可能就是您要寻找的。​​span>
  • A TimeoutException 不是 AggregateException,这就是你不进入 catch 区域的原因。您必须手动创建一个包含超时异常的 AggregateException ...请参阅下面的答案。干杯。

标签: c# exception aggregate


【解决方案1】:

您需要在内部异常上调用Handle。来自MSDN's documentationHandle

谓词的每次调用都返回 true 或 false 以指示是否处理了异常。在所有调用之后,如果有任何异常未处理,所有未处理的异常将被放入一个新的 AggregateException 中,该异常将被抛出。否则,Handle 方法简单地返回。如果谓词的任何调用引发异常,它将停止处理任何更多异常并立即按原样传播引发的异常。

示例代码,同样来自 MSDN:

public static void Main()
{
    var task1 = Task.Run(() => { throw new CustomException("This exception is expected!"); });

    try 
    {
        task1.Wait();
    }
    catch (AggregateException ae)
    {
        // Call the Handle method to handle the custom exception,
        // otherwise rethrow the exception.
        ae.Handle(ex => 
        { 
            if (ex is CustomException)
                Console.WriteLine(ex.Message);
            return ex is CustomException;
        });
    }
}

【讨论】:

    【解决方案2】:

    AggregateException 通常用于捕获异常,这可能在等待 Task 完成时发生。因为Task一般可以包含多个其他的,我们不知道是否会抛出一个或多个异常。

    检查以下示例:

    // set up your task
    Action<int> job = (int i) =>
    {
        if (i % 100 == 0)
            throw new TimeoutException("i = " + i);
    };
    
    // we want many tasks to run in paralell
    var tasks = new Task[1000];
    for (var i = 0; i < 1000; i++)
    {
        // assign to other variable,
        // or it will use the same number for every task
        var j = i; 
        // run your task
        var task = Task.Run(() => job(j));
        // save it
        tasks[i] = task;
    }
    
    try
    {
        // wait for all the tasks to finish in a blocking manner
        Task.WaitAll(tasks);
    
    }
    catch (AggregateException e)
    {
        // catch whatever was thrown
        foreach (Exception ex in e.InnerExceptions)
            Console.WriteLine(ex.Message);
    }
    

    【讨论】:

      【解决方案3】:

      我的解决方法:

      var tasks = new Task[] { DoSomethingAsync(), DoSomethingElseAsync() };
      
      try
      {
          await Task.WhenAll(tasks).ConfigureAwait(false);
      }
      catch (AggregateException ex)
      {
          var flatAgrExs = ex.Flatten().InnerExceptions;
      
          foreach(var agrEx in flatAgrExs)
          {
              //handle out errors
              logger.LogError(agrEx, "Critical Error occurred");
          }
      }
      

      【讨论】:

        【解决方案4】:

        这里是实际使用 AggregateException 从异常对象中获取内部异常,

            private static Exception GetFirstRealException(Exception exception)
            {
                Exception realException = exception;
                var aggregateException = realException as AggregateException;
        
                if (aggregateException != null)
                {
                    realException = aggregateException.Flatten().InnerException; // take first real exception
        
                    while (realException != null && realException.InnerException != null)
                    {
                        realException = realException.InnerException;
                    }
                }
        
                return realException ?? exception;
            }
        

        【讨论】:

          【解决方案5】:

          使用 Parallel 时,“作业”(此处从 0 到 500000 计数)被拆分到多个工作线程上。 这些中的每一个都可能引发异常。在示例中,异常被编码为在 10523 上工作的线程中发生。 在现实世界的场景中,可能会发生多个异常(在不同的线程中) - AggregateException 只是 Parallel 运行时发生的所有异常的“容器”,因此您不会丢失任何异常...

          【讨论】:

          • 是的,这很好,但我不明白为什么我得到一个“错误”,说用户代码没有处理超时异常。不应该聚合异常捕获此异常并在并行完成其工作后将其打印到控制台?
          • 你是对的,但我认为你描述的行为只是在调试时在 VS 中运行时发生的。
          • @Dan:我通过在 VS 外部运行您的示例并且没有 catch 块得到的异常是 AggregateException:发生了一个或多个错误。
          • 我不明白 - 你为什么在没有 catch 块的情况下运行?
          • @Klinger 我不明白你想说什么。我应该怎么做才能处理这个异常?
          猜你喜欢
          • 1970-01-01
          • 2011-09-07
          • 1970-01-01
          • 1970-01-01
          • 2021-09-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多