Une exception dans les méthodes asynchrones n’est pas interceptée

Le code suivant ct.ThrowIfCancellationRequested pas mon OperationCancelException qui est levée en appelant ct.ThrowIfCancellationRequested .

 public partial class TitleWindow : Window, IAsyncInitialization { public Task Initialization{get; private set;} CancellationTokenSource cts; public TitleWindow() { InitializeComponent(); cts = new CancellationTokenSource(); } private void Window_Loaded(object sender, RoutedEventArgs e) { try { cts.Cancel(); Initialization = GetCancelExceptionAsync(cts.Token); } catch (OperationCanceledException) { Console.WriteLine("Operation canceled!"); } } public async Task GetCancelExceptionAsync(CancellationToken ct) { await Task.Delay(1000); ct.ThrowIfCancellationRequested(); } } 

Cependant, si je remplace ma méthode Window_Loaded par ce qui suit (la rendant asynchrone et attendant l’appel de ma méthode asynchrone), l’exception est interceptée.

 private async void Window_Loaded(object sender, RoutedEventArgs e) { try { cts.Cancel(); await GetCancelExceptionAsync(cts.Token); } catch (OperationCanceledException) { Console.WriteLine("Operation canceled!"); } } 

Pourquoi ma première approche ne fonctionne-t-elle pas? L’exception n’est-elle pas propagée correctement dans le contexte de synchronisation correct?

J’essayais d’utiliser The Asynchronous Initialization Pattern décrit dans l’ article de blog de Stephen Clearys pour pouvoir attendre plus tard une tâche démarrée dans un constructeur (et afin de le rendre comparable à mon deuxième exemple, j’ai utilisé l’événement ( async ) Window_Loaded attendre les méthodes immédiatement, comme cela m’a été suggéré dans une question précédente ). Ensuite, je souhaitais fournir une option permettant d’annuler la méthode async que j’avais lancée dans le constructeur, où je suis actuellement bloqué car la gestion des exceptions ne fonctionne pas comme prévu.

Avec mon code «non fonctionnel», je peux attraper l’exception en plaçant l’ await Initialization dans un bloc try-catch quelque part, mais j’obtiens toujours une exception supplémentaire non gérée.

Comment puis-je implémenter cela d’une manière qui me permet d’attendre ma méthode asynchrone ultérieurement (pour éviter que je ne travaille avec un état incohérent de mon object) et d’être toujours en mesure d’annuler cette tâche longue (qui besoin de retourner / définir les valeurs par défaut)?

Dans votre premier exemple, l’exception n’est pas interceptée car elle ne survient pas avant de quitter le bloc try/catch . Si vous voulez y accéder, vous devez attendre / await exactement comme vous le feriez dans le deuxième exemple. Si vous n’attendez pas la tâche renvoyée, la méthode continue son exécution et quitte le bloc try/catch avant que l’exception ne se produise réellement …

Si vous voulez intercepter l’exception “hors bande”, vous pouvez également vous inscrire à TaskScheduler.UnobservedTaskException (cet événement est appelé si une tâche TaskScheduler.UnobservedTaskException une exception qui n’est pas interceptée) pour obtenir toutes les exceptions non interceptées ou surveiller la propriété Exception tâches. Peut également consulter cette réponse.

L’exception est lancée dans la tâche sur un autre thread.

 public async Task GetCancelExceptionAsync(CancellationToken ct) { try { await Task.Delay(1000); ct.ThrowIfCancellationRequested(); } catch (Exception e) { // your Cancleation expeption } }