Delen via


Het Asynchrone patroon op basis van gebeurtenissen implementeren

Als u een klasse schrijft met een aantal bewerkingen die merkbare vertragingen kunnen ondervinden, kunt u overwegen deze asynchrone functionaliteit te geven door het Asynchrone patroon op basis van gebeurtenissen te implementeren.

Het Asynchrone patroon op basis van gebeurtenissen biedt een gestandaardiseerde manier om een klasse met asynchrone functies te verpakken. Als deze is geïmplementeerd met helperklassen zoals AsyncOperationManager, werkt uw klasse correct onder elk toepassingsmodel, waaronder ASP.NET, Consoletoepassingen en Windows Forms-toepassingen.

Voor een voorbeeld waarin het Asynchrone patroon op basis van gebeurtenissen wordt geïmplementeerd, raadpleegt u How to: Implement a Component That Supports the Event-based Asynchronous Pattern.

Voor eenvoudige asynchrone bewerkingen is het BackgroundWorker onderdeel mogelijk geschikt. Zie Procedure: Een bewerking uitvoeren op de achtergrond voor meer informatie.BackgroundWorker

In de volgende lijst worden de functies van het Asynchrone patroon op basis van gebeurtenissen beschreven in dit onderwerp.

  • Mogelijkheden voor het implementeren van het Asynchrone patroon op basis van gebeurtenissen

  • Asynchrone methoden benoemen

  • Optioneel annulering van ondersteuning

  • Optioneel ondersteuning voor de eigenschap IsBusy

  • Optioneel ondersteuning bieden voor voortgangsrapportage

  • Optioneel ondersteuning bieden voor het retourneren van incrementele resultaten

  • Out- en refparameters verwerken in methoden

Mogelijkheden voor het implementeren van het Asynchrone patroon op basis van gebeurtenissen

Overweeg om het Asynchrone patroon op basis van gebeurtenissen te implementeren wanneer:

  • Clients van uw klasse hebben geen objecten nodig WaitHandle en IAsyncResult zijn niet beschikbaar voor asynchrone bewerkingen, wat betekent dat polling en WaitAll of WaitAny moeten worden opgebouwd door de client.

  • U wilt dat asynchrone bewerkingen worden beheerd door de client met het vertrouwde gebeurtenis-/gemachtigde model.

Elke bewerking is een kandidaat voor een asynchrone implementatie, maar de bewerkingen die u verwacht lange latenties te hebben, moeten worden overwogen. Met name geschikt zijn bewerkingen waarbij clients een methode aanroepen en bij voltooiing hiervan op de hoogte worden gesteld, zonder verdere tussenkomst vereist. Ook geschikt zijn bewerkingen die continu worden uitgevoerd, waarbij clients periodiek op de hoogte worden gesteld van de voortgang, incrementele resultaten of statuswijzigingen.

Zie Bepalen wanneer u het Asynchrone patroon op basis van gebeurtenissen wilt implementeren voor meer informatie over het bepalen wanneer u het Asynchrone patroon op basis van gebeurtenissen wilt implementeren.

Asynchrone methoden benoemen

Voor elke synchrone methode MethodName waarvoor u een asynchrone tegenhanger wilt opgeven:

Definieer een MethodNameAsync-methode die:

  • Retourneert void.

  • Neemt dezelfde parameters als de MethodName-methode .

  • Accepteert meerdere aanroepen.

U kunt desgewenst een overbelasting van MethodNameAsync definiëren, identiek aan MethodNameAsync, maar met een extra parameter met objectwaarde genaamduserState. Doe dit als u bereid bent om meerdere gelijktijdige aanroepen van uw methode te beheren. In dat geval wordt de userState waarde teruggestuurd naar alle gebeurtenishandlers om aanroepen van de methode te onderscheiden. U kunt dit ook doen als een locatie om de gebruikersstatus op te slaan voor later ophalen.

Voor elke afzonderlijke methodNameAsync-methodehandtekening :

  1. Definieer de volgende gebeurtenis in dezelfde klasse als de methode:

    Public Event MethodNameCompleted As MethodNameCompletedEventHandler
    
    public event MethodNameCompletedEventHandler MethodNameCompleted;
    
  2. Definieer de volgende gemachtigde en AsyncCompletedEventArgs. Deze worden waarschijnlijk buiten de klasse zelf gedefinieerd, maar in dezelfde naamruimte.

    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 Property
    
    public delegate void MethodNameCompletedEventHandler(object sender,
        MethodNameCompletedEventArgs e);
    
    public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
    {
        public MyReturnType Result { get; }
    }
    
    • Zorg ervoor dat de klasse MethodNameCompletedEventArgs de leden zichtbaar maakt als alleen-lezeneigenschappen en niet als velden, omdat velden gegevensbinding voorkomen.

    • Definieer geen AsyncCompletedEventArgsafgeleide klassen voor methoden die geen resultaten produceren. Gebruik gewoon een exemplaar van AsyncCompletedEventArgs zichzelf.

      Notitie

      Het is perfect acceptabel, indien haalbaar en passend, om gedelegeerden en AsyncCompletedEventArgs typen opnieuw te gebruiken. In dit geval is de naamgeving niet zo consistent met de naam van de methode, omdat een bepaalde gemachtigde niet AsyncCompletedEventArgs is gekoppeld aan één methode.

Optioneel annulering van ondersteuning

Als uw klasse ondersteuning biedt voor het annuleren van asynchrone bewerkingen, moet de annulering worden blootgesteld aan de client, zoals hieronder wordt beschreven. Er zijn twee beslissingspunten die moeten worden bereikt voordat u uw annuleringsondersteuning definieert:

  • Heeft uw klas, inclusief toekomstige verwachte toevoegingen, slechts één asynchrone bewerking die annulering ondersteunt?
  • Kunnen de asynchrone bewerkingen die ondersteuning bieden voor annulering, meerdere bewerkingen in behandeling ondersteunen? Dat wil zeggen, neemt de MethodNameAsync-methode een userState parameter en staat het meerdere aanroepen toe voordat wordt gewacht totdat deze is voltooid?

Gebruik de antwoorden op deze twee vragen in de onderstaande tabel om te bepalen wat de handtekening voor uw annuleringsmethode moet zijn.

Visual Basic

Meerdere gelijktijdige bewerkingen ondersteund Slechts één bewerking tegelijk
Eén Async-bewerking in de hele klasse Sub MethodNameAsyncCancel(ByVal userState As Object) Sub MethodNameAsyncCancel()
Meerdere asynchrone bewerkingen in klasse Sub CancelAsync(ByVal userState As Object) Sub CancelAsync()

C#

Meerdere gelijktijdige bewerkingen ondersteund Slechts één bewerking tegelijk
Eén Async-bewerking in de hele klasse void MethodNameAsyncCancel(object userState); void MethodNameAsyncCancel();
Meerdere asynchrone bewerkingen in klasse void CancelAsync(object userState); void CancelAsync();

Als u de CancelAsync(object userState) methode definieert, moeten clients voorzichtig zijn bij het kiezen van hun statuswaarden, zodat ze onderscheid kunnen maken tussen alle asynchrone methoden die op het object worden aangeroepen, en niet alleen tussen alle aanroepen van één asynchrone methode.

De beslissing om de single-async-operation version MethodNameAsyncCancel te noemen, is gebaseerd op het gemakkelijker detecteren van de methode in een ontwerpomgeving, zoals IntelliSense van Visual Studio. Hiermee worden de gerelateerde leden gegroepeerd en onderscheiden ze zich van andere leden die niets te maken hebben met asynchrone functionaliteit. Als u verwacht dat er mogelijk extra asynchrone bewerkingen worden toegevoegd in volgende versies, is het beter om te definiëren CancelAsync.

Definieer niet meerdere methoden uit de bovenstaande tabel in dezelfde klasse. Dat zal niet logisch zijn, of het zal de klasse-interface met een verspreiding van methoden onbelangrijke e-mail.

Deze methoden worden meestal onmiddellijk geretourneerd en de bewerking kan al dan niet daadwerkelijk worden geannuleerd. In de gebeurtenis-handler voor de gebeurtenis MethodNameCompleted bevat het object MethodNameCompletedEventArgs een Cancelled veld dat clients kunnen gebruiken om te bepalen of de annulering is opgetreden.

Houd zich aan de annuleringssemantiek die wordt beschreven in aanbevolen procedures voor het implementeren van het Asynchrone Asynchrone patroon op basis van gebeurtenissen.

Optioneel ondersteuning voor de eigenschap IsBusy

Als uw klasse geen ondersteuning biedt voor meerdere gelijktijdige aanroepen, kunt u overwegen een IsBusy eigenschap beschikbaar te maken. Hierdoor kunnen ontwikkelaars bepalen of een MethodNameAsync-methode wordt uitgevoerd zonder een uitzondering van de MethodNameAsync-methode te ondervangen.

Houd zich aan de IsBusy semantiek die wordt beschreven in aanbevolen procedures voor het implementeren van het Asynchrone patroon op basis van gebeurtenissen.

Optioneel ondersteuning bieden voor voortgangsrapportage

Het is vaak wenselijk dat een asynchrone bewerking de voortgang tijdens de bewerking rapporteert. Het Asynchrone patroon op basis van gebeurtenissen biedt hiervoor een richtlijn.

  • U kunt eventueel een gebeurtenis definiëren die moet worden gegenereerd door de asynchrone bewerking en wordt aangeroepen op de juiste thread. Het ProgressChangedEventArgs object bevat een voortgangsindicator met een geheel getal dat naar verwachting tussen 0 en 100 ligt.

  • Noem deze gebeurtenis als volgt:

    • ProgressChanged als de klasse meerdere asynchrone bewerkingen heeft (of naar verwachting meerdere asynchrone bewerkingen bevat in toekomstige versies);

    • MethodNameProgressChanged als de klasse één asynchrone bewerking heeft.

    Deze naamgevingskeuze parallelleert die zijn gemaakt voor de annuleringsmethode, zoals beschreven in de sectie Optioneel ondersteuning voor annulering.

Voor deze gebeurtenis moeten de handtekening voor gemachtigden ProgressChangedEventHandler en de ProgressChangedEventArgs klasse worden gebruikt. Als er ook een meer domeinspecifieke voortgangsindicator kan worden opgegeven (bijvoorbeeld bytes lezen en totaal aantal bytes voor een downloadbewerking), moet u een afgeleide klasse van ProgressChangedEventArgsdefiniëren.

Houd er rekening mee dat er slechts één ProgressChanged of MethodNameProgressChanged-gebeurtenis voor de klasse is, ongeacht het aantal asynchrone methoden dat wordt ondersteund. Clients gebruiken naar verwachting het userState object dat wordt doorgegeven aan de MethodNameAsync-methoden om onderscheid te maken tussen voortgangsupdates voor meerdere gelijktijdige bewerkingen.

Er kunnen situaties zijn waarin meerdere bewerkingen de voortgang ondersteunen en elk een andere indicator retourneert voor de voortgang. In dit geval is één ProgressChanged gebeurtenis niet geschikt en kunt u overwegen meerdere ProgressChanged gebeurtenissen te ondersteunen. In dit geval gebruikt u een naamgevingspatroon van MethodNameProgressChanged voor elke MethodNameAsync-methode .

Houd zich aan de semantiek voor voortgangsrapportage die aanbevolen procedures voor het implementeren van het Asynchrone patroon op basis van gebeurtenissen wordt beschreven.

Optioneel ondersteuning bieden voor het retourneren van incrementele resultaten

Soms kan een asynchrone bewerking incrementele resultaten retourneren voordat deze is voltooid. Er zijn een aantal opties die kunnen worden gebruikt om dit scenario te ondersteunen. Hier volgen enkele voorbeelden.

Klasse voor één bewerking

Als uw klasse slechts één asynchrone bewerking ondersteunt en die bewerking incrementele resultaten kan retourneren, dan:

  • Breid het ProgressChangedEventArgs type uit om de incrementele resultaatgegevens te dragen en definieer een MethodNameProgressChanged-gebeurtenis met deze uitgebreide gegevens.

  • Verhoog deze MethodNameProgressChanged-gebeurtenis wanneer er een incrementeel resultaat is om te rapporteren.

Deze oplossing is specifiek van toepassing op een klasse met één asynchrone bewerking, omdat er geen probleem is met dezelfde gebeurtenis die optreedt om incrementele resultaten op alle bewerkingen te retourneren, zoals de gebeurtenis MethodNameProgressChanged wel doet.

Klasse met meerdere bewerkingen met homogene incrementele resultaten

In dit geval ondersteunt uw klasse meerdere asynchrone methoden, die elk geschikt zijn voor het retourneren van incrementele resultaten en deze incrementele resultaten hebben allemaal hetzelfde type gegevens.

Volg het hierboven beschreven model voor klassen met één bewerking, omdat dezelfde EventArgs structuur werkt voor alle incrementele resultaten. Definieer een ProgressChanged gebeurtenis in plaats van een MethodNameProgressChanged-gebeurtenis , omdat deze van toepassing is op meerdere asynchrone methoden.

Klasse met meerdere bewerkingen met heterogene incrementele resultaten

Als uw klasse meerdere asynchrone methoden ondersteunt, moet u het volgende doen:

  • Scheid uw incrementele resultaatrapportage van uw voortgangsrapportage.

  • Definieer een afzonderlijke MethodNameProgressChanged-gebeurtenis met de juiste EventArgs methode voor elke asynchrone methode om de incrementele resultaatgegevens van die methode af te handelen.

Roep die gebeurtenis-handler aan op de juiste thread, zoals beschreven in Aanbevolen procedures voor het implementeren van het Asynchrone patroon op basis van gebeurtenissen.

Out- en refparameters verwerken in methoden

Hoewel het gebruik van out en ref in het algemeen wordt afgeraden in .NET, zijn dit de regels die moeten worden gevolgd wanneer ze aanwezig zijn:

Gegeven een synchrone methode MethodName:

  • out parameters voor MethodName mogen geen deel uitmaken van MethodNameAsync. In plaats daarvan moeten ze deel uitmaken van MethodNameCompletedEventArgs met dezelfde naam als het parameter-equivalent in MethodName (tenzij er een meer geschikte naam is).

  • ref parameters voor MethodName moeten worden weergegeven als onderdeel van MethodNameAsync en als onderdeel van MethodNameCompletedEventArgs met dezelfde naam als het parameterequivalent in MethodName (tenzij er een meer geschikte naam is).

Bijvoorbeeld:

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);

Uw asynchrone methode en de AsyncCompletedEventArgs bijbehorende klasse zien er als volgt uit:

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

Zie ook