2015-04-24 5 views
1

Просто заметили странную вещь: поймать исключение в вызывающем абоненте из новой задачи, лямбда ДОЛЖНА быть отмечена как async !? Действительно ли это необходимо, даже если у делегата нет ожидающих операторов?Обработка исключений за пределами задачи

try 
    { 
     //Task.Run(() =>  // exception is not caught! 
     Task.Run(async() => // unnecessary async!?! 
     { 
      throw new Exception("Exception in Task"); 
     }).Wait(); 
    } 
    catch (Exception ex) 
    { 
     res = ex.Message; 
    } 

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

Добавлен полный код:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var p = new Program(); 
     p.Run(); 
    } 

public void Run() 
{ 
    string result; 

    try 
    { 
     result = OnSomeEvent((s, ea) => RunSomeTask()); 
    } 
    catch (Exception ex) // Try to catch unhandled exceptions here! 
    { 
     result = ex.Message; 
    } 

    Console.WriteLine(result); 
    Console.ReadKey(); 
} 

// Some other Framework bult-in event (can not change signature) 
public string OnSomeEvent(EventHandler e) 
{ 
    e.Invoke(null, new EventArgs()); 
    return "OK"; 
} 

private async Task RunSomeTask() 
{ 
    await Task.Run(async() => // do not need async here!!! 
    //await Task.Run(() =>  // caller do not catches exceptions (but must) 
    { 
     throw new Exception("Exception in Task1"); 
    }); 
} 
} 

Так qestion это как catche отл. без asyn ключевое слово ???

+0

Вам не нужно использовать 'async' - я подозреваю, что исключение исключает прерывание вывода типа делегата. Попробуйте явно указать тип делегата. – Lee

+2

Вы говорите * исключение не поймали! * Когда асинхронный режим не используется. Но на самом деле это поймано. Это ваш фактический код? –

+0

@ Ли верно. Я помню, как несколько месяцев назад читал дубликат по этой точной теме. Выбрасывание исключения изменяет тип возврата анонимного делегата. –

ответ

0

При использовании async/await, исключения автоматически разворачиваются на сайте await. При использовании и .Wait() любое исключение завершается, когда они выходят из Task, и, таким образом, получение информации требует, чтобы вы выкапывали в свойство Task.Exception, поскольку они не распространяют стек вызовов.

См https://dotnetfiddle.net/MmEXsT

+0

В конкретном случае независимо от того, что я использую «wait» или «wait». Я тестировал оба. – Arvis

+0

Полностью забыл, что это было в собственности - обновил мой anser таким образом – David

1

методы, которые возвращают Task - такие, как Task.Run или async методов - разместит какие-либо исключения по этому вернулся Task. Вам решать это исключение. Обычно это делается с await, как это:

await Task.Run(() => { throw ... }); 

В вашем случае, проблема в этой строке:

result = OnSomeEvent((s, ea) => RunSomeTask()); 

В этом коде RunSomeTask возвращается в Task, и что Task никогда ожидается. Чтобы наблюдать за исключением, вы должны выполнить эту задачу await.

+0

, где вы предложили поставить этот оператор «ждут»? Becouse отредактируйте это так: 'result = OnSomeEvent (async (s, ea) => ожидание RunSomeTask());' не поймать ex. либо, он становится лямбдой, что возвращает «пустоту». – Arvis

+0

@Arvis: Вы должны переосмыслить свое решение.То, что вы пытаетесь сделать прямо сейчас, - это sync-over-async, известный анти-шаблон. Вам придется либо сделать ваш код полностью асинхронным, либо сохранить задачу где-то и отреагировать на нее позже. –