Поведение, которое вы видите, вероятно, является ошибкой в крайнем случае или даже может быть правильным, если оно не интуитивно понятно.Обычно, когда вы вызываете асинхронный метод синхронно, он оборачивает задачу для ее выполнения, и поскольку никто не ожидает завершения задачи, исключение никогда не попадает в основной поток.Если бы вы вызывали Main напрямую, это бы успешно, но тогда ваша среда выполнения увидела бы исключение «success» в другом потоке.
Поскольку main - это точка входа вашего приложения, она вызывается синхронно и, вероятно, какточка входа не запускает поведение переноса задач, поэтому await не запускается должным образом, и TaskEx.Run создает собственный поток, который отображается во время выполнения как исключение, генерируемое в другом потоке.
Если бы вы запускали main как метод async
, то есть возвращали Task
(поскольку async
, который возвращает void
, действительно можно вызвать только через await
) и блокировали его из вашего синхронного основного контекста,вы получите соответствующее поведение, как показано в приведенном ниже тесте:
static async Task Main() {
try {
await TaskEx.Run(() => { throw new Exception("failure"); });
} catch(Exception) {
throw new Exception("success");
}
}
static async Task Main2() {
await Main();
}
[Test]
public void CallViaAwait() {
var t = Main2();
try {
t.Wait();
Assert.Fail("didn't throw");
} catch(AggregateException e) {
Assert.AreEqual("success",e.InnerException.Message);
}
}
[Test]
public void CallDirectly() {
var t = Main();
try {
t.Wait();
Assert.Fail("didn't throw");
} catch(AggregateException e) {
Assert.AreEqual("success", e.InnerException.Message);
}
}
Т.е. Задача дает сбой с AggregateException
, который содержит исключение success в качестве внутреннего исключения.