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 } }