Ответ 1
Теперь С# 6 поддерживает await
в catch
и finally
, поэтому код можно записать так, как я этого хотел; обходной путь больше не нужен.
Тот факт, что мы не можем использовать ключевое слово await
в блоках catch
, делает довольно неудобным отображение сообщений об ошибках из методов async в WinRT, так как API MessageDialog
является асинхронным. В идеале я хотел бы написать это:
private async Task DoSomethingAsync()
{
try
{
// Some code that can throw an exception
...
}
catch (Exception ex)
{
var dialog = new MessageDialog("Something went wrong!");
await dialog.ShowAsync();
}
}
Но вместо этого я должен написать это следующим образом:
private async Task DoSomethingAsync()
{
bool error = false;
try
{
// Some code that can throw an exception
...
}
catch (Exception ex)
{
error = true;
}
if (error)
{
var dialog = new MessageDialog("Something went wrong!");
await dialog.ShowAsync();
}
}
Все методы, необходимые для этого, должны следовать аналогичному шаблону, который мне действительно не нравится, потому что он уменьшает читаемость кода.
Есть ли лучший способ справиться с этим?
EDIT: Я придумал это (что похоже на то, что подсказывает в комментариях):
static class Async
{
public static async Task Try(Func<Task> asyncAction)
{
await asyncAction();
}
public static async Task Catch<TException>(this Task task, Func<TException, Task> handleExceptionAsync, bool rethrow = false)
where TException : Exception
{
TException exception = null;
try
{
await task;
}
catch (TException ex)
{
exception = ex;
}
if (exception != null)
{
await handleExceptionAsync(exception);
if (rethrow)
ExceptionDispatchInfo.Capture(exception).Throw();
}
}
}
Использование:
private async Task DoSomethingAsync()
{
await Async.Try(async () =>
{
// Some code that can throw an exception
...
})
.Catch<Exception>(async ex =>
{
var dialog = new MessageDialog("Something went wrong!");
await dialog.ShowAsync();
});
}
.Catch<...>
вызовы могут быть закодированы, чтобы имитировать несколько блоков catch
.
Но я не очень доволен этим решением; синтаксис еще более неудобен, чем раньше...
Теперь С# 6 поддерживает await
в catch
и finally
, поэтому код можно записать так, как я этого хотел; обходной путь больше не нужен.
у вас уже есть эта функциональность в TPL
await Task.Run(async () =>
{
// Some code that can throw an exception
...
}).ContinueWith(async (a) =>
{
if (a.IsFaulted)
{
var dialog = new MessageDialog("Something went wrong!\nError: "
+ a.Exception.Message);
await dialog.ShowAsync();
}
else
{
var dialog2 = new MessageDialog("Everything is OK: " + a.Result);
await dialog2.ShowAsync();
}
}).Unwrap();
В этой машине у меня нет Windows 8, поэтому я тестировал в Windows 7, но я думаю, что это то же самое. *Редактировать как указано в комментариях, необходимых .Unwrap(); в конце для ожидания работы