繁体   English   中英

AggregateException C# 示例

[英]AggregateException C# example

我在 web 上看到了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());
        }
    }
}

您需要在内部异常上调用Handle 来自MSDN关于Handle的文档:

谓词的每次调用都返回 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;
        });
    }
}

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

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

下面是实际使用 AggregateException 从异常 object 中获取内部异常,

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

我的解决方法:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM