代码之家  ›  专栏  ›  技术社区  ›  alfoks

重新引发AggregateException的内部异常

  •  0
  • alfoks  · 技术社区  · 6 年前

    假设我有一个接口:

    interface A {
        string Do();
    }
    

    然后我在一个类中实现这个接口。实现需要一些异步操作。如下所示:

    class B : A {
        public string Do() {
            return Task1().Result;
        }
    
        private async Task<string> Task1() {
            var str = await Task2();
    
            return str + "task1";
        }
    
        private async Task<string> Task2() {
            using (WebClient client = new WebClient())
            {
                return System.Text.Encoding.UTF8.GetString(await client.DownloadDataTaskAsync(new Uri("http://test.com")));
            }
        }
    }
    

    将异步操作链中发生的第一个异常返回到外部调用代码的正确方法是什么?以下是一个好方法吗?

    public string Do() {
        try {
            return Task1().Result;
        } catch (AggregateException ex) {
            Exception inner = ex;
            while(inner.InnerException != null) {
                inner = inner.InnerException;
            }
    
            throw inner;
        }
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Antoine V    6 年前

    从你的代码,通过 while ,我想你想把第一个例外 AggregateException 要做到这一点,你可以使用 Flatten

    将AggregateException实例展平为单个新实例。

    它有助于将异常置于“相同的层次结构”中,然后您可以简单地调用 FirstOrDefault 获取第一个异常。

    假设此代码:

    Task.Factory.StartNew(
            async () =>
            {
                await Task.Factory.StartNew(
                    () => { throw new Exception("inner"); },
                    TaskCreationOptions.AttachedToParent);
    
                throw new Exception("outer");
            }).Wait();
        }
    

    例外的结构

    AggregateException
        Exception: outer
        AggregateException
           Exception: inner
    

    Flatten 我可以得到 inner

    catch(AggregateException ex)
    {
         Console.WriteLine(ex.Flatten().InnerExceptions.FirstOrDefault().Message);
    }
    

    但是没有 压扁 我得到 聚合例外 ,这不正确

    Catch(聚合异常)
    {
    console.writeline(例如flatten().innerExceptions.firstOrDefault().message);
    }
    

    对于您的案例,这一行可以帮助您获得第一个异常

    ex.Flatten().InnerExceptions.FirstOrDefault().Message
    

    你也有方法 Handle ,帮助您处理内部异常 聚合例外

    catch (AggregateException ex)
    {
        ex.Handle(x =>
        {
            if (x is UnauthorizedAccessException)
            {
                //the exception you interested
                throw x;           
            }
            // Other exceptions will not be handled here.
            //some action i.e log
            return false;
        });
    }
    
    推荐文章