Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier les répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer de répertoire.
Si vous écrivez une classe avec certaines opérations susceptibles d’entraîner des retards notables, envisagez de lui donner des fonctionnalités asynchrones en implémentant le modèle asynchrone basé sur les événements.
Le modèle asynchrone basé sur les événements fournit un moyen standardisé de empaqueter une classe qui a des fonctionnalités asynchrones. Si elle est implémentée avec des classes d’assistance telles que AsyncOperationManager, votre classe fonctionne correctement sous n’importe quel modèle d’application, y compris les applications ASP.NET, les applications console et les applications Windows Forms.
Pour obtenir un exemple qui implémente le modèle asynchrone basé sur les événements, consultez Guide pratique pour implémenter un composant prenant en charge le modèle asynchrone basé sur les événements.
Pour les opérations asynchrones simples, vous pouvez trouver le BackgroundWorker composant approprié. Pour plus d’informations sur BackgroundWorker, consultez Guide pratique pour exécuter une opération en arrière-plan.
La liste suivante décrit les fonctionnalités du modèle asynchrone basé sur les événements abordés dans cette rubrique.
Opportunités d’implémentation du modèle asynchrone basé sur les événements
Affectation de noms à des méthodes asynchrones
Prise en charge facultative de l’annulation
Prise en charge facultative de la propriété IsBusy
Fournir éventuellement la prise en charge des rapports d’avancement
Fournir éventuellement la prise en charge du retour des résultats incrémentiels
Gestion des paramètres Out et Ref dans les méthodes
Opportunités d’implémentation du modèle asynchrone basé sur les événements
Envisagez d’implémenter le modèle asynchrone basé sur les événements quand :
Les clients de votre classe n’ont pas besoin WaitHandle et IAsyncResult les objets disponibles pour les opérations asynchrones, ce qui signifie que l’interrogation et WaitAll ou WaitAny doit être générée par le client.
Vous souhaitez que les opérations asynchrones soient gérées par le client avec le modèle d’événement/délégué familier.
Toute opération est candidate à une implémentation asynchrone, mais celles que vous prévoyez d’entraîner de longues latences doivent être prises en compte. Particulièrement approprié, les opérations dans lesquelles les clients appellent une méthode et sont avertis à la fin, sans intervention supplémentaire requise. Il convient également d’effectuer des opérations qui s’exécutent en continu, en informant régulièrement les clients de la progression, des résultats incrémentiels ou des modifications d’état.
Pour plus d’informations sur la prise en charge du modèle asynchrone basé sur les événements, voir Quand implémenter le modèle asynchrone basé sur les événements.
Affectation de noms à des méthodes asynchrones
Pour chaque méthode synchrone MethodName pour laquelle vous souhaitez fournir un équivalent asynchrone :
Définissez une méthode Async MethodName qui :
Retourne
void.Prend les mêmes paramètres que la méthode MethodName .
Accepte plusieurs appels.
Définissez éventuellement une surcharge Async MethodName, identique à MethodNameAsync, mais avec un paramètre d’objet supplémentaire appelé userState. Pour ce faire, si vous êtes prêt à gérer plusieurs appels simultanés de votre méthode, auquel cas la userState valeur est remise à tous les gestionnaires d’événements pour distinguer les appels de la méthode. Vous pouvez également choisir de le faire simplement en tant qu’emplacement pour stocker l’état utilisateur pour une récupération ultérieure.
Pour chaque signature de méthode Async MethodName distincte :
Définissez l’événement suivant dans la même classe que la méthode :
Public Event MethodNameCompleted As MethodNameCompletedEventHandlerpublic event MethodNameCompletedEventHandler MethodNameCompleted;Définissez le délégué suivant et AsyncCompletedEventArgs. Celles-ci seront probablement définies en dehors de la classe elle-même, mais dans le même espace de noms.
Public Delegate Sub MethodNameCompletedEventHandler( _ ByVal sender As Object, _ ByVal e As MethodNameCompletedEventArgs) Public Class MethodNameCompletedEventArgs Inherits System.ComponentModel.AsyncCompletedEventArgs Public ReadOnly Property Result() As MyReturnType End Propertypublic delegate void MethodNameCompletedEventHandler(object sender, MethodNameCompletedEventArgs e); public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { public MyReturnType Result { get; } }Vérifiez que la classe MethodNameCompletedEventArgs expose ses membres en tant que propriétés en lecture seule, et non en tant que champs, car les champs empêchent la liaison de données.
Ne définissez AsyncCompletedEventArgsaucune classe dérivée pour les méthodes qui ne produisent pas de résultats. Utilisez simplement une instance de AsyncCompletedEventArgs lui-même.
Remarque
Il est parfaitement acceptable, lorsque cela est possible et approprié, de réutiliser les délégués et AsyncCompletedEventArgs les types. Dans ce cas, le nommage ne sera pas aussi cohérent avec le nom de la méthode, car un délégué donné et AsyncCompletedEventArgs ne sera pas lié à une seule méthode.
Prise en charge facultative de l’annulation
Si votre classe prend en charge l’annulation d’opérations asynchrones, l’annulation doit être exposée au client, comme décrit ci-dessous. Il existe deux points de décision à atteindre avant de définir votre support d’annulation :
- Votre classe, y compris les ajouts prévus à venir, n’a-t-elle qu’une seule opération asynchrone qui prend en charge l’annulation ?
- Les opérations asynchrones qui prennent en charge l’annulation prennent-elles en charge plusieurs opérations en attente ? Autrement dit, la méthode Async MethodName prend-elle un
userStateparamètre et autorise-t-elle plusieurs appels avant d’attendre la fin d’une opération ?
Utilisez les réponses à ces deux questions dans le tableau ci-dessous pour déterminer la signature de votre méthode d’annulation.
Visual Basic
| Plusieurs opérations simultanées prises en charge | Une seule opération à la fois | |
|---|---|---|
| Une opération asynchrone dans toute la classe | Sub MethodNameAsyncCancel(ByVal userState As Object) |
Sub MethodNameAsyncCancel() |
| Opérations asynchrones multiples dans la classe | Sub CancelAsync(ByVal userState As Object) |
Sub CancelAsync() |
C#
| Plusieurs opérations simultanées prises en charge | Une seule opération à la fois | |
|---|---|---|
| Une opération asynchrone dans toute la classe | void MethodNameAsyncCancel(object userState); |
void MethodNameAsyncCancel(); |
| Opérations asynchrones multiples dans la classe | void CancelAsync(object userState); |
void CancelAsync(); |
Si vous définissez la CancelAsync(object userState) méthode, les clients doivent être prudents lors du choix de leurs valeurs d’état pour les rendre capables de distinguer toutes les méthodes asynchrones appelées sur l’objet, et pas seulement entre tous les appels d’une seule méthode asynchrone.
La décision de nommer la version mono-async-operation MethodNameAsyncCancel est basée sur la possibilité de découvrir plus facilement la méthode dans un environnement de conception comme IntelliSense de Visual Studio. Cela regroupe les membres associés et les distingue des autres membres qui n’ont rien à voir avec les fonctionnalités asynchrones. Si vous pensez qu’il peut y avoir des opérations asynchrones supplémentaires ajoutées dans les versions suivantes, il est préférable de définir CancelAsync.
Ne définissez pas plusieurs méthodes du tableau ci-dessus dans la même classe. Cela n’aura pas de sens, ou il encombre l’interface de classe avec une prolifération de méthodes.
Ces méthodes retournent généralement immédiatement, et l’opération peut ou non être annulée. Dans le gestionnaire d’événements de l’événement MethodNameCompleted , l’objet MethodNameCompletedEventArgs contient un Cancelled champ, que les clients peuvent utiliser pour déterminer si l’annulation s’est produite.
Respectez la sémantique d’annulation décrite dans Les meilleures pratiques pour l’implémentation du modèle asynchrone basé sur les événements.
Prise en charge facultative de la propriété IsBusy
Si votre classe ne prend pas en charge plusieurs appels simultanés, envisagez d’exposer une IsBusy propriété. Cela permet aux développeurs de déterminer si une méthode MethodNameAsync est en cours d’exécution sans intercepter une exception de la méthode MethodNameAsync .
Respectez la IsBusy sémantique décrite dans Les meilleures pratiques pour l’implémentation du modèle asynchrone basé sur les événements.
Fournir éventuellement la prise en charge des rapports d’avancement
Il est fréquemment souhaitable qu’une opération asynchrone signale la progression pendant son opération. Le modèle asynchrone basé sur les événements fournit des instructions pour ce faire.
Définissez éventuellement un événement à lever par l’opération asynchrone et appelé sur le thread approprié. L’objet ProgressChangedEventArgs porte un indicateur de progression à valeur entière qui doit être compris entre 0 et 100.
Nommez cet événement comme suit :
ProgressChangedsi la classe a plusieurs opérations asynchrones (ou devrait augmenter pour inclure plusieurs opérations asynchrones dans les versions ultérieures) ;MethodNameProgressChanged si la classe a une seule opération asynchrone.
Ce choix de nommage parallèles faits pour la méthode d’annulation, comme décrit dans la section Annulation de prise en charge facultative.
Cet événement doit utiliser la ProgressChangedEventHandler signature de délégué et la ProgressChangedEventArgs classe. Sinon, si un indicateur de progression plus spécifique au domaine peut être fourni (par exemple, les octets lus et le total d’octets pour une opération de téléchargement), vous devez définir une classe dérivée de ProgressChangedEventArgs.
Notez qu’il n’existe qu’un ProgressChanged ou un événement ProgressChanged MethodName pour la classe, quel que soit le nombre de méthodes asynchrones qu’elle prend en charge. Les clients sont censés utiliser l’objet userState passé aux méthodes AsyncMethodName pour distinguer les mises à jour de progression sur plusieurs opérations simultanées.
Il peut y avoir des situations dans lesquelles plusieurs opérations prennent en charge la progression et chacun retourne un indicateur différent pour la progression. Dans ce cas, un seul ProgressChanged événement n’est pas approprié et vous pouvez envisager de prendre en charge plusieurs ProgressChanged événements. Dans ce cas, utilisez un modèle d’affectation de noms de MethodNameProgressChanged pour chaque méthode Async MethodName.
Respectez la sémantique de création de rapports de progression décrites dans les meilleures pratiques d’implémentation du modèle asynchrone basé sur les événements.
Fournir éventuellement la prise en charge du retour des résultats incrémentiels
Parfois, une opération asynchrone peut retourner des résultats incrémentiels avant la fin. Il existe plusieurs options qui peuvent être utilisées pour prendre en charge ce scénario. Voici quelques exemples.
Classe à opération unique
Si votre classe prend uniquement en charge une seule opération asynchrone et que cette opération est en mesure de retourner des résultats incrémentiels, puis :
Étendez le ProgressChangedEventArgs type pour transporter les données de résultat incrémentielles et définissez un événement MethodNameProgressChanged avec ces données étendues.
Déclenchez cet événement MethodNameProgressChanged lorsqu’il existe un résultat incrémentiel à signaler.
Cette solution s’applique spécifiquement à une classe d’opération asynchrone unique, car il n’existe aucun problème avec le même événement qui se produit pour retourner des résultats incrémentiels sur « toutes les opérations », car l’événement MethodNameProgressChanged le fait.
Classe à opérations multiples avec des résultats incrémentiels homogènes
Dans ce cas, votre classe prend en charge plusieurs méthodes asynchrones, chacune capable de retourner des résultats incrémentiels, et ces résultats incrémentiels ont tous le même type de données.
Suivez le modèle décrit ci-dessus pour les classes à opération unique, car la même EventArgs structure fonctionnera pour tous les résultats incrémentiels. Définissez un ProgressChanged événement au lieu d’un événement MethodNameProgressChanged , car il s’applique à plusieurs méthodes asynchrones.
Classe à opérations multiples avec des résultats incrémentiels hétérogènes
Si votre classe prend en charge plusieurs méthodes asynchrones, chacune retournant un type de données différent, vous devez :
Séparez vos rapports de résultats incrémentiels de vos rapports de progression.
Définissez un événement MethodNameProgressChanged distinct approprié EventArgs pour chaque méthode asynchrone pour gérer les données de résultat incrémentielles de cette méthode.
Appelez ce gestionnaire d’événements sur le thread approprié, comme décrit dans Best Practices for Implementing the Event-based Asynchrone Pattern.
Gestion des paramètres Out et Ref dans les méthodes
Bien que l’utilisation et outref soit, en général, découragée dans .NET, voici les règles à suivre lorsqu’elles sont présentes :
Étant donné une méthode synchrone , MethodName :
outles paramètres de MethodName ne doivent pas faire partie de MethodNameAsync. Au lieu de cela, ils doivent faire partie de MethodNameCompletedEventArgs portant le même nom que son paramètre équivalent dans MethodName (sauf s’il existe un nom plus approprié).refles paramètres de MethodName doivent apparaître dans le cadre d’AsyncMethodName et, dans le cadre de MethodNameCompletedEventArgs portant le même nom que son paramètre équivalent dans MethodName (sauf s’il existe un nom plus approprié).
Par exemple, étant donné :
Public Function MethodName(ByVal arg1 As String, ByRef arg2 As String, ByRef arg3 As String) As Integer
public int MethodName(string arg1, ref string arg2, out string arg3);
Votre méthode asynchrone et sa AsyncCompletedEventArgs classe ressemblent à ceci :
Public Sub MethodNameAsync(ByVal arg1 As String, ByVal arg2 As String)
Public Class MethodNameCompletedEventArgs
Inherits System.ComponentModel.AsyncCompletedEventArgs
Public ReadOnly Property Result() As Integer
End Property
Public ReadOnly Property Arg2() As String
End Property
Public ReadOnly Property Arg3() As String
End Property
End Class
public void MethodNameAsync(string arg1, string arg2);
public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
public int Result { get; };
public string Arg2 { get; };
public string Arg3 { get; };
}
Voir aussi
- ProgressChangedEventArgs
- AsyncCompletedEventArgs
- Guide pratique pour implémenter un composant prenant en charge le modèle asynchrone basé sur les événements
- Comment : exécuter une opération en arrière-plan
- Comment : implémenter un formulaire qui utilise une opération en arrière-plan
- 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
- Modèle asynchrone basé sur les événements (EAP)