Обработка исключений из синхронной части асинхронного метода
Я имею дело с ситуацией, когда запускаемая мною задача может выполняться одновременно с одновременным выполнением в начальном потоке. Примерно так, в иллюстративных целях:
static async Task TestAsync()
{
var random = new Random(Environment.TickCount).Next();
if (random % 2 != 0)
throw new ApplicationException("1st");
await Task.Delay(2000);
Console.WriteLine("after await Task.Delay");
throw new ApplicationException("2nd");
}
Из телефонного кода яЯ хотел бы иметь возможность ловить любые исключения, возможно, выброшенные из синхронной части (т.е. доawait Task.Delay()
). Вот'как яВ настоящее время я делаю это:
static void Main(string[] args)
{
try
{
var task = TestAsync();
if (task.IsFaulted)
task.GetAwaiter().GetResult();
Console.WriteLine("TestAsync continues asynchronously...");
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.ToString());
}
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
Это работает, хотя выглядит немного глотком, так как нетResult
на .I 'Task
мы также пыталисьtask.Wait()
вместоtask.GetAwaiter().GetResult()
, Это всегда дает мнеAggregateException
который я должен развернуть (а не как ожидалосьApplicationException
напрямую).
Есть ли другие варианты?
[EDITED] Чтобы ответить на комментарии: я делаю это, потому что, если задача не удается мгновенно, я неЯ не хочу добавлять его в список ожидающих выполнения задач, которые я поддерживаю. Сама задача ничего не знает о таком списке (и она нет) Я все еще хочу зарегистрировать исключение и информировать об этом пользователя. Я мог бы также сделатьthrow task.Exception
но это неt дать кадр стека исключений, захваченный с.ExceptionDispatchInfo
[ОБНОВИТЬ] Вдохновлен другими ответами и комментариями: если у меня есть полный контроль надTestAsync
и я неЯ не хочу представлять новых учеников, я также мог бы сделать что-то вроде ниже. Это может пригодиться при проверке аргументов:
static Task TestAsync(int delay)
{
if (delay < 0)
throw new ArgumentOutOfRangeException("delay");
Func asyncPart = async () =>
{
Console.WriteLine("await Task.Delay");
await Task.Delay(delay);
throw new ApplicationException("2nd");
};
return asyncPart();
}