Мне интересно, как я могу позволить этому коду попасть в catch
из PassThrough
?
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main(string[] args)
{
try
{
await PassThrough(Test());
} catch (Exception) {
Console.WriteLine("caught at invocation");
}
Console.ReadLine();
}
public static async Task PassThrough(Task<bool> test)
{
try
{
var result = await test.ConfigureAwait(false);
// still need to do something with result here...
}
catch
{
Console.WriteLine("never caught... :(");
}
}
/// external code!
public static Task<bool> Test()
{
throw new Exception("something bad");
// do other async stuff here
// ...
return Task.FromResult(true);
}
}
Внешний код должен возвращать дескриптор пути ошибки и возвращать Task.FromException
?
Передать Func<Task<bool>>
?
@BradleyUffner обновлено
Добавление к ответу Дуглас.
Перехватывайте исключения только в том случае, если вы можете сделать с ними что-то значимое и можете управлять ими на этом уровне.
Task.FromException
в основном просто помещает исключение в задачу, которую вы обычно возвращаете. Однако в этом случае Шаблон асинхронного ожидания уже делает это за вас. т. е. если вы просто позволите ему потерпеть неудачу, исключение все равно будет помещено в задачу, поэтому, похоже, в вашем коде нет реальной причины что-либо ловить.
Единственное подходящее место, где вы должны думать о перехвате исключений, находится в async void
, поскольку они выполняются незаметно и могут вызывать проблемы при возникновении исключения.
Я бы порекомендовал изменить ваш метод PassThrough
, чтобы взять Func<Task<bool>>
вместо Task<bool>
. Таким образом, вы можете перехватывать исключения, возникающие как в синхронной части вашего метода Test
, так и в асинхронной задаче, которую он запускает. Дополнительным преимуществом является то, что асинхронные методы (определенные с помощью async
и await
) могут быть напрямую приведены к Func<Task>
или Func<Task<TResult>>
.
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
try
{
await PassThrough(Test);
// Note that we are now passing in a function delegate for Test,
// equivalent to () => Test(), not its result.
}
catch (Exception)
{
Console.WriteLine("caught at invocation");
}
Console.ReadLine();
}
public static async Task PassThrough(Func<Task<bool>> test)
{
try
{
var task = test(); // exception thrown here
var result = await task.ConfigureAwait(false);
// still need to do something with result here...
}
catch
{
Console.WriteLine("caught in PassThrough");
}
}
/// external code!
public static Task<bool> Test()
{
throw new Exception("something bad");
// do other async stuff here
// ...
return Task.FromResult(true);
}
}
В следующей строке вы ожидаете PassThrough
, а не Test
.
await PassThrough(Test());
Вы можете ждать обоих, если хотите:
await PassThrough(await Test()); // also need to change the signature of PassThrough from Task<bool> to bool.
... но в обоих случаях Test
будет вызываться первым. И поскольку он выдает исключение, PassThrough
никогда не будет вызван. По этой причине вы не видите сообщение "пойман в PassThrough". Выполнение никогда не входит в этот метод.
Вероятно, вам также следует изменить точку входа на
public static async Task Main()
, если вы используете версию фреймворка, которая ее поддерживает.