2014-03-29 4 views
8

normal behavior для исключений, отбрасываемых из методов async Task, заключается в том, чтобы оставаться бездействующими до тех пор, пока они не будут обнаружены позже или пока задача не будет собрана мусором.Сбрасывание немедленно из метода асинхронного метода

Я могу придумать случаи, когда я могу немедленно бросить. Вот пример:

public static async Task TestExAsync(string filename) 
{ 
    // the file is missing, but it may be there again 
    // when the exception gets observed 5 seconds later, 
    // hard to debug 

    if (!System.IO.File.Exists(filename)) 
     throw new System.IO.FileNotFoundException(filename); 

    await Task.Delay(1000); 
} 

public static void Main() 
{ 
    var task = TestExAsync("filename"); 
    try 
    { 
     Thread.Sleep(5000); // do other work 
     task.Wait(); // wait and observe 
    } 
    catch (AggregateException ex) 
    { 
     Console.WriteLine(new { ex.InnerException.Message, task.IsCanceled }); 
    } 
    Console.ReadLine(); 
} 

я мог бы использовать async void, чтобы обойти эту проблему, которая бросает сразу:

// disable the "use await" warning 
#pragma warning disable 1998 
public static async void ThrowNow(Exception ex) 
{ 
    throw ex; 
} 
#pragma warning restore 1998 

public static async Task TestExAsync(string filename) 
{ 
    if (!System.IO.File.Exists(filename)) 
     ThrowNow(new System.IO.FileNotFoundException(filename)); 

    await Task.Delay(1000); 
} 

Теперь я могу обработать это исключение прямо на месте с Dispatcher.UnhandledException или AppDomain.CurrentDomain.UnhandledException, по крайней мере, немедленно принесите его вниманию пользователя.

Есть ли другие варианты для этого сценария? Возможно, это надуманная проблема?

+1

Мой голос за надуманную проблему. :) В идеале асинхронный код будет реагировать, поэтому время между сбоем задачи и наблюдением за ошибкой этой задачи должно быть очень коротким. –

+0

Голосовать признано, tks :) – Noseratio

ответ

4

Если вы действительно хотите сделать это, вы можете использовать тот же подход, Джон Скит used in his reimplementation of LINQ: создать синхронный метод, который может бросить или вызывать реальный асинхронный метод:

public static Task TestExAsync(string filename) 
{ 
    if (!System.IO.File.Exists(filename)) 
     throw new System.IO.FileNotFoundException(filename); 

    return TestExAsyncImpl(filename); 
} 

private static async Task TestExAsyncImpl(string filename) 
{ 
    await Task.Delay(1000); 
} 

Имейте в виду, что я думаю, что это нормально предположить, что метод возврата Task не бросает напрямую. Например, вы можете использовать Task.WhenAll() для получения всех исключений из нескольких операций при нормальных обстоятельствах, но этот подход не будет работать, если исключение будет немедленно отправлено.

1

Я думаю, что нормальное поведение является подходящим. Ваша нить зависит от результат функции async для выполнения следующей обработки, поэтому исключение должно быть выбрано в вашей теме. Код вашей последовательности может принять соответствующие меры для восстановления из исключения. Поскольку вы можете передавать свои задачи и инициировать множество задач, код восстановления может находиться в где-то еще, где вам нужно получить результат задачи, чем ваш исходный код. Если исключение сразу же выбрано, его можно было бы выбросить за пределами вашего кода восстановления.

Функция недействительности asynch действует немедленно, что имеет смысл, потому что ничто не зависит от ее результата, и нет никакой задачи, чтобы пройти.

BTW, задача обработки исключений заключается в том, чтобы восстановить состояние приложения из исключений, не должно перехватывать исключения, которые невозможно восстановить. Когда генерируется исключение, состояние вашего приложения может быть повреждено, попытка продолжить работу с поврежденными приложениями вызывает больше проблем и уязвимостей безопасности.

+0

* «... не следует перехватывать исключения, которые невозможно восстановить» * - это точно моя точка с отсутствующим примером файла. Я бы предпочел, чтобы пользователь прекратил приложение прямо там, чем через 5 секунд (или никогда, если ошибка в моем коде и задача никогда не наблюдаются). В противном случае я согласен, но я бы хотел, чтобы этот вопрос зависал еще немного, чтобы понять, что могут подумать другие. – Noseratio

+0

@Noseratio: в случае, если приложение может восстановиться после исключения, мы не должны его прекращать. Это моя точка зрения. Когда другой код использует ваш код, другой код может восстановиться из исключения. –

+0

Я думаю, что это не случай с моим примером.Если другой код (который наблюдает за исключением в будущем) попытается восстановиться, вместо него будет отсутствовать * другой * файл. Это может привести к потере данных. Проверьте [«Исключения Vexing» Эрика Липперта] (http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx). – Noseratio

Смежные вопросы