重新抛出 AggregateException 的内部异常

Rethrowing inner exception of an AggregateException

假设我有一个接口:

interface A {
    string Do();
}

然后我在class中实现了这个接口。该实现需要一些异步操作。类似于以下内容:

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")));
        }
    }
}

对于外部调用代码,异步操作链中发生的第一个异常,return的正确方法是什么?以下是一个好的方法吗?

public string Do() {
    try {
        return Task1().Result;
    } catch (AggregateException ex) {
        Exception inner = ex;
        while(inner.InnerException != null) {
            inner = inner.InnerException;
        }

        throw inner;
    }
}

根据你的代码,通过 while,我认为你想在 AggregateException 中抛出第一个异常 为此,您可以使用 Flatten

Flattens an AggregateException instances into a single, new instance.

将异常放在 "the same hierarchy" 中会有所帮助,然后您可以简单地调用 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);
}

但没有 Flatten,我得到 AggregateException,这是不正确的

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

对于你的情况,这一行可以帮助你得到第一个异常

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

你还有方法Handle,可以帮你处理AggregateException

里面的异常
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;
    });
}