2014-11-12 3 views
3

Я знаю, что этот вопрос задавался несколько раз, но я немного смотрю на другой вариант.Обработка исключений в методах async C#

public async Task<string> SomeAsyncMethod(string url) 
{ 
    // do some URL validation 
    if (!valid) 
    { 
      throw new Exception("some error"); 
    } 
    // do async stuff now 
    return await GetFromUrl(url) 
} 

// now in caller 
public async Task<string> SomeOtherAsyncMethod(string input) 
{ 
    var task = SomeAsyncMethod(input); 
    // there is potential chance that a validation fails and 
    //exception is thrown even before entering async parts of the called function 

    // do some independent stuff here 
    try 
    { 
     await task; 
    } 
    catch(Exception e) 
    { 
     // log error 
    } 

    // is the following code correct way to handle exceptions? 
    if (!task.IsFaulted) 
    { 
     return task.Result; 
    } 

    // log error from task.Exception 
    return null; 

} 

В приведенном выше коде может случиться так, что проверка терпит неудачу, и исключение даже до того, как управление входит асинхронную часть способа. Нужно ли обернуть первый вызов также вокруг блока try..catch? Мой эксперимент показал, что это не полезно. Вместо этого для статуса задачи задано значение Faulted. Поэтому я считаю правильным проверить состояние задачи и соответственно вернуть данные. Может ли C# прокомментировать это?

+0

Действительно ли SomeAsyncMethod() должен быть 'async'? Не можете ли вы просто вернуть GetFromUrl (url); '? – piedar

+0

@piedar .. да, это должно быть асинхронно. Это операция ввода-вывода и, следовательно, нет точки в блочном ожидании. – Gopal

+0

@Gopal: просто возврат значения из 'GetFromUrl (url)' не будет блокироваться. Он просто вернул бы «Задача », этот метод вернулся вместо того, чтобы обернуть задачу в еще одну задачу. Разница заключалась бы в том, что вместо исключения, попадающего в оболочку задачи, вызывающий элемент 'SomeOtherAsyncMethod' увидит это. Что лучше зависит от ваших предпочтений: упаковка реализации SomeAsyncMethod в задаче упрощает обработку исключений в вызывающем, но при незначительном расходе дополнительных накладных расходов (задача, конечный автомат метода и т. Д.). Либо мне кажется хорошо. –

ответ

3

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

3

Нужно ли обертывать первый вызов и вокруг блока try..catch?

Возможно, вы захотите сделать это в качестве защитной меры кодирования. Исключения «Предварительное условие» в методах async страдают от тех же проблем, что и с блоками перечислителя. В случае async для исключения задачи используются исключения предварительного условия, которые не возникают напрямую. Вот как я делаю предварительные исключения.

Однако есть альтернатива. Возможно, что реализация «с нетерпением» выполнит проверки предварительных условий и использует только неисправные задачи для представления асинхронных исключений. I.e .:

public Task<string> SomeMethodAsync(string url) 
{ 
    // do some URL validation 
    if (!valid) 
    { 
    throw new Exception("some error"); 
    } 
    // do async stuff now 
    return SomeMethodImplAsync(url); 
} 

private async Task<string> SomeMethodImplAsync(string url) 
{ 
    return await GetFromUrl(url) 
} 

Я не делаю этого сам, но у такого подхода есть свои сторонники. В первую очередь, Джон Скит.

Имея это в виду, если в документации явно не указано, что предположения об условном условии будут помещены в возвращаемую задачу, вероятно, вы должны включить вызов в SomeMethdAsync в блок try.

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