Пример AggregateException С#
Я видел пример 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());
}
}
}
Ответы
Ответ 1
Вам нужно вызвать 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;
});
}
}
Ответ 2
При использовании Parallel "задание" (здесь от 0 до 500000) делится на несколько рабочих потоков.
Каждое из них может вызвать исключение. В образце исключение кодируется в потоке, работающем на 10523.
В сценарии реального мира может произойти не одно исключение (в разных потоках) - AggregateException - это всего лишь "контейнер" для всех исключений, возникающих при запуске Parallel, чтобы вы не потеряли никакого исключения...
Ответ 3
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);
}
Ответ 4
Посмотрите следующий пример:
http://richhewlett.com/2010/05/12/raising-multiple-exceptions-with-aggregateexception/
Он дает несколько примеров как объединить исключения в исключении AggregateException.
Ответ 5
Вот практическое использование 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;
}
Ответ 6
Мой способ решить это:
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");
}
}