Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Le modèle asynchrone basé sur les événements vous offre un moyen efficace d’exposer le comportement asynchrone dans les classes, avec une sémantique d’événement et de délégué familière. Pour implémenter un modèle asynchrone basé sur des événements, vous devez respecter certaines exigences comportementales spécifiques. Les sections suivantes décrivent les exigences et les instructions à prendre en compte lorsque vous implémentez une classe qui suit le modèle asynchrone basé sur les événements.
Pour obtenir une vue d’ensemble, consultez Implémentation du modèle asynchrone basé sur les événements.
Garanties comportementales requises
Si vous implémentez le modèle asynchrone basé sur les événements, vous devez fournir un certain nombre de garanties pour vous assurer que votre classe se comporte correctement et que les clients de votre classe peuvent s’appuyer sur ce comportement.
Achèvement
Appelez toujours le gestionnaire d’événements MethodNameCompleted lorsque vous terminez avec succès, rencontrez une erreur, ou effectuez une annulation. Les applications ne doivent jamais rencontrer une situation où elles restent inactives et ne se terminent jamais. Une exception à cette règle est si l’opération asynchrone elle-même est conçue afin qu’elle ne se termine jamais.
Événement Completed et classe EventArgs
Pour chaque méthode Async MethodName distincte, appliquez les exigences de conception suivantes :
Définissez un événement MethodNameCompleted sur la même classe que la méthode.
Définissez une EventArgs classe et un délégué associé pour l’événement MethodNameCompleted qui dérive de la AsyncCompletedEventArgs classe. Le nom de classe par défaut doit être de la forme MethodNameCompletedEventArgs.
Vérifiez que la EventArgs classe est spécifique aux valeurs de retour de la méthode MethodName . Lorsque vous utilisez la EventArgs classe, vous ne devez jamais demander aux développeurs de caster le résultat.
L’exemple de code suivant montre respectivement une bonne et mauvaise implémentation de cette exigence de conception.
// Good design
private void Form1_MethodNameCompleted(object sender, xxxCompletedEventArgs e)
{
DemoType result = e.Result;
}
// Bad design
private void Form1_MethodNameCompleted(object sender, MethodNameCompletedEventArgs e)
{
DemoType result = (DemoType)(e.Result);
}
Ne définissez pas de EventArgs classe pour retourner des méthodes qui retournent
void
. Utilisez plutôt une instance de la AsyncCompletedEventArgs classe.Vérifiez que vous déclenchez toujours l’événement MethodNameCompleted . Cet événement doit être déclenché quand l'opération s'est terminée correctement, ou bien en cas d'erreur ou d'annulation. Les applications ne doivent jamais rencontrer une situation où elles restent inactives et ne se terminent jamais.
Vérifiez que vous interceptez toutes les exceptions qui se produisent dans l’opération asynchrone et affectez l’exception interceptée à la Error propriété.
En cas d’erreur lors de la fin de la tâche, les résultats ne doivent pas être accessibles. Lorsque la propriété Error n'est pas
null
, assurez-vous que l'accès à n'importe quelle propriété dans la structure EventArgs déclenche une exception. Utilisez la RaiseExceptionIfNecessary méthode pour effectuer cette vérification.Modélisez un délai au terme duquel une erreur se produit. Quand un délai arrive à expiration, déclenchez l’événement NomMéthodeCompleted et affectez une TimeoutException à la propriété Error.
Si votre classe prend en charge plusieurs appels simultanés, vérifiez que l’événement MethodNameCompleted contient l’objet approprié
userSuppliedState
.Vérifiez que l’événement MethodNameCompleted est déclenché sur le thread approprié et au moment approprié du cycle de vie de l’application. Pour plus d’informations, consultez la section Threading and Contexts.
Exécution simultanée d’opérations
Si votre classe prend en charge plusieurs appels simultanés, permettez au développeur de suivre chaque appel séparément en définissant la surcharge MethodNameAsync qui prend un paramètre d'état à valeur d'objet ou un ID de tâche, appelé
userSuppliedState
. Ce paramètre doit toujours être le dernier paramètre de la signature de la méthode MethodNameAsync .Si votre classe définit la surcharge MethodNameAsync qui prend un paramètre d’état à valeur d’objet ou un ID de tâche, assurez-vous de suivre la durée de vie de l’opération avec cet ID de tâche, et veillez à le réinjecter dans le gestionnaire d’achèvement. Il existe des classes d’assistance disponibles pour aider. Pour plus d’informations sur la gestion de la concurrence, consultez Guide pratique pour implémenter un composant prenant en charge le modèle asynchrone basé sur les événements.
Si votre classe définit la méthode Async MethodName sans paramètre d’état et qu’elle ne prend pas en charge plusieurs appels simultanés, assurez-vous que toute tentative d’appeler MethodNameAsync avant que l’appel async MethodName précédent n’ait terminé génère un InvalidOperationException.
En règle générale, ne déclenchez pas d’exception si la méthode Async MethodName sans le
userSuppliedState
paramètre est appelée plusieurs fois afin qu’il existe plusieurs opérations en attente. Vous pouvez lever une exception quand votre classe ne peut pas explicitement gérer cette situation, mais partez du principe que les développeurs peuvent gérer ces différents rappels impossibles à distinguer.
Accès aux résultats
En cas d’erreur lors de l’exécution de l’opération asynchrone, les résultats ne doivent pas être accessibles. Vérifiez que l'accès à n'importe quelle propriété de AsyncCompletedEventArgs lorsque Error n'est pas
null
déclenche l'exception référencée par Error. La AsyncCompletedEventArgs classe fournit la RaiseExceptionIfNecessary méthode à cet effet.Vérifiez que toute tentative d’accès au résultat déclenche une InvalidOperationException déclaration indiquant que l’opération a été annulée. Utilisez la AsyncCompletedEventArgs.RaiseExceptionIfNecessary méthode pour effectuer cette vérification.
Rapport de progression
Prendre en charge les rapports de progression, si possible. Cela permet aux développeurs de fournir une meilleure expérience utilisateur d’application lorsqu’ils utilisent votre classe.
Si vous implémentez un événement ProgressChanged ou MethodNameProgressChanged , vérifiez qu’aucun événement de ce type n’est déclenché pour une opération asynchrone particulière après l’événement MethodNameCompleted de cette opération.
Si la norme ProgressChangedEventArgs est en cours de remplissage, assurez-vous que le ProgressPercentage peut toujours être interprété comme un pourcentage. Le pourcentage n’a pas besoin d’être précis, mais il doit représenter un pourcentage. Si votre métrique de rapport de progression doit être autre qu’un pourcentage, dérivez une classe de la ProgressChangedEventArgs classe et laissez ProgressPercentage à 0. Évitez d’utiliser une métrique de création de rapports autre qu’un pourcentage.
Vérifiez que l’événement
ProgressChanged
est déclenché sur le thread approprié et au moment approprié dans le cycle de vie de l’application. Pour plus d’informations, consultez la section Threading and Contexts.
Implémentation d’IsBusy
N’exposez pas de
IsBusy
propriété si votre classe prend en charge plusieurs appels simultanés. Par exemple, les proxys de service Web XML n’exposent pas deIsBusy
propriété, car ils prennent en charge plusieurs appels simultanés de méthodes asynchrones.La
IsBusy
propriété doit retournertrue
une fois la méthode AsyncMethodName appelée et avant que l’événement MethodNameCompleted ait été déclenché. Sinon, il doit retournerfalse
. Les composants BackgroundWorker et WebClient sont des exemples de classes qui exposent uneIsBusy
propriété.
Annulation
Dans la mesure du possible, prenez en charge l'annulation. Cela permet aux développeurs de fournir une meilleure expérience utilisateur d’application lorsqu’ils utilisent votre classe.
Dans le cas de l’annulation, définissez l’indicateur Cancelled dans l’objet AsyncCompletedEventArgs .
Vérifiez que toute tentative d’accès au résultat déclenche une InvalidOperationException déclaration indiquant que l’opération a été annulée. Utilisez la AsyncCompletedEventArgs.RaiseExceptionIfNecessary méthode pour effectuer cette vérification.
Assurez-vous que les appels d'une méthode d'annulation réussissent toujours et qu'ils ne déclenchent jamais d'exception. En règle générale, un client n’est pas averti de savoir si une opération est réellement annulable à un moment donné et n’est pas avertie de la réussite d’une annulation précédemment émise. Toutefois, l’application reçoit toujours une notification lorsqu’une annulation est réussie, car l’application contribue à la gestion de l’état d’achèvement.
Déclenchez l’événement MethodNameCompleted lorsque l’opération est annulée.
Erreurs et exceptions
- Interceptez toutes les exceptions qui se produisent dans l’opération asynchrone et définissez la valeur de la AsyncCompletedEventArgs.Error propriété sur cette exception.
Thread et contextes
Pour une opération correcte de votre classe, il est essentiel que les gestionnaires d’événements du client soient appelés sur le thread ou le contexte appropriés pour le modèle d’application donné, y compris les applications ASP.NET et Windows Forms. Deux classes d’assistance importantes sont fournies pour vous assurer que votre classe asynchrone se comporte correctement sous n’importe quel modèle d’application : AsyncOperation et AsyncOperationManager.
AsyncOperationManager fournit une méthode, CreateOperationqui retourne un AsyncOperation. Votre méthode MethodNameAsync appelle CreateOperation et votre classe utilise la valeur renvoyée AsyncOperation pour suivre la durée de vie de la tâche asynchrone.
Pour signaler la progression, les résultats incrémentiels et l’achèvement au client, appelez les méthodes Post et OperationCompleted sur le AsyncOperation. AsyncOperation prend en charge le marshaling des appels des gestionnaires d’événements du client en thread ou contexte adéquat.
Remarque
Vous pouvez contourner ces règles si vous souhaitez explicitement aller à l'encontre de la politique du modèle d'application, mais bénéficier quand même des autres avantages de l'utilisation du schéma asynchrone basé sur les événements. Par exemple, vous pouvez souhaiter qu'une classe fonctionnant dans Windows Forms soit libre de threads. Vous pouvez créer une classe threadée libre, tant que les développeurs comprennent les restrictions implicites. Les applications console ne synchronisent pas l’exécution des Post appels. Cela peut entraîner le déclenchement d'événements ProgressChanged
dans le désordre. Si vous souhaitez avoir sérialisé l’exécution des Post appels, implémentez et installez une System.Threading.SynchronizationContext classe.
Pour plus d’informations sur l’utilisation AsyncOperation et l’activation de vos opérations asynchrones, consultez AsyncOperationManager.
Lignes directrices
Dans l’idéal, chaque appel de méthode doit être indépendant des autres. Vous devez éviter de combiner des appels avec des ressources partagées. Si les ressources doivent être partagées entre les appels, vous devez fournir un mécanisme de synchronisation approprié dans votre implémentation.
Les conceptions qui nécessitent que le client implémente la synchronisation sont déconseillées. Par exemple, vous pouvez avoir une méthode asynchrone qui reçoit un objet statique global en tant que paramètre ; plusieurs appels simultanés de cette méthode peuvent entraîner une altération des données ou des interblocages.
Si vous implémentez une méthode avec la surcharge d’appel multiple (
userState
dans la signature), votre classe devra gérer une collection d’états utilisateur ou d’ID de tâche et leurs opérations en attente correspondantes. Cette collection doit être protégée avec des régionslock
, car les différents appels ajoutent et suppriment des objetsuserState
dans la collection.Envisagez de réutiliser les
CompletedEventArgs
classes lorsque cela est possible et approprié. Dans ce cas, le nommage n’est pas cohérent avec le nom de la méthode, car un délégué et EventArgs un type donnés ne sont pas liés à une seule méthode. Toutefois, forcer les développeurs à caster la valeur récupérée à partir d'une propriété sur le EventArgs n'est jamais acceptable.Si vous créez une classe qui dérive de Component, n’implémentez pas et installez votre propre SynchronizationContext classe. Les modèles d’application, et non les composants, contrôlent ce SynchronizationContext qui est utilisé.
Lorsque vous utilisez le multithreading de n’importe quelle sorte, vous vous exposez potentiellement à des bogues très graves et complexes. Avant d’implémenter une solution qui utilise le multithreading, consultez les meilleures pratiques en matière de threads managés.
Voir aussi
- AsyncOperation
- AsyncOperationManager
- AsyncCompletedEventArgs
- ProgressChangedEventArgs
- BackgroundWorker
- Implémentation du modèle asynchrone basé sur les événements
- Modèle asynchrone basé sur les événements (EAP)
- Choix du moment où implémenter le modèle asynchrone basé sur les événements
- Meilleures pratiques pour l’implémentation du modèle asynchrone basé sur les événements
- Guide pratique pour utiliser des composants qui prennent en charge le modèle asynchrone basé sur les événements
- Guide pratique pour implémenter un composant prenant en charge le modèle asynchrone basé sur les événements