Aanbevolen procedures voor het implementeren van het Asynchrone patroon op basis van gebeurtenissen
Het Asynchrone patroon op basis van gebeurtenissen biedt u een effectieve manier om asynchroon gedrag beschikbaar te maken in klassen, met vertrouwde gebeurtenissen en semantiek delegeren. Als u Asynchroon patroon op basis van gebeurtenissen wilt implementeren, moet u een aantal specifieke gedragsvereisten volgen. In de volgende secties worden de vereisten en richtlijnen beschreven die u moet overwegen wanneer u een klasse implementeert die volgt op het Asynchrone patroon op basis van gebeurtenissen.
Zie Het Asynchrone patroon op basis van gebeurtenissen implementeren voor een overzicht.
Vereiste gedragsgaranties
Als u het Asynchrone patroon op basis van gebeurtenissen implementeert, moet u een aantal garanties opgeven om ervoor te zorgen dat uw klasse zich correct gedraagt en clients van uw klasse op dergelijk gedrag kunnen vertrouwen.
Voltooiing
Roep altijd de gebeurtenis-handler MethodNameCompleted aan wanneer u de voltooiing, een fout of annulering hebt voltooid. Toepassingen mogen nooit een situatie tegenkomen waarin ze niet actief blijven en de voltooiing nooit plaatsvindt. Een uitzondering op deze regel is als de asynchrone bewerking zelf zo is ontworpen dat deze nooit wordt voltooid.
Voltooide gebeurtenis en EventArgs
Voor elke afzonderlijke MethodNameAsync-methode past u de volgende ontwerpvereisten toe:
Definieer een gebeurtenis MethodNameCompleted in dezelfde klasse als de methode.
Definieer een EventArgs klasse en bijbehorende gemachtigde voor de gebeurtenis MethodNameCompleted die is afgeleid van de AsyncCompletedEventArgs klasse. De standaardklassenaam moet van de form MethodNameCompletedEventArgs zijn.
Zorg ervoor dat de EventArgs klasse specifiek is voor de retourwaarden van de MethodName-methode . Wanneer u de EventArgs klasse gebruikt, moet u nooit vereisen dat ontwikkelaars het resultaat casten.
In het volgende codevoorbeeld ziet u respectievelijk een goede en slechte implementatie van deze ontwerpvereiste.
// 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);
}
Definieer EventArgs geen klasse voor retourmethoden die retourneren
void
. Gebruik in plaats daarvan een exemplaar van de AsyncCompletedEventArgs klasse.Zorg ervoor dat u altijd de gebeurtenis MethodNameCompleted opheft. Deze gebeurtenis moet worden gegenereerd bij geslaagde voltooiing, bij een fout of bij annulering. Toepassingen mogen nooit een situatie tegenkomen waarin ze niet actief blijven en de voltooiing nooit plaatsvindt.
Zorg ervoor dat u eventuele uitzonderingen in de asynchrone bewerking onderschept en de gevangen uitzondering toewijst aan de Error eigenschap.
Als er een fout is opgetreden bij het voltooien van de taak, mogen de resultaten niet toegankelijk zijn. Als de Error eigenschap niet
null
is, moet u ervoor zorgen dat toegang tot een eigenschap in de EventArgs structuur een uitzondering genereert. Gebruik de RaiseExceptionIfNecessary methode om deze verificatie uit te voeren.Modelleer een time-out als een fout. Wanneer er een time-out optreedt, verhoogt u de gebeurtenis MethodNameCompleted en wijst u een TimeoutException aan de Error eigenschap toe.
Als uw klasse meerdere gelijktijdige aanroepen ondersteunt, moet u ervoor zorgen dat de gebeurtenis MethodNameCompleted het juiste
userSuppliedState
object bevat.Zorg ervoor dat de gebeurtenis MethodNameCompleted wordt gegenereerd op de juiste thread en op het juiste moment in de levenscyclus van de toepassing. Zie de sectie Threading en Contexten voor meer informatie.
Gelijktijdig uitvoeren van bewerkingen
Als uw klasse meerdere gelijktijdige aanroepen ondersteunt, stelt u de ontwikkelaar in staat om elke aanroep afzonderlijk bij te houden door de overbelasting van MethodName Async te definiëren die een parameter voor de objectwaarde of taak-id gebruikt, genaamd .
userSuppliedState
Deze parameter moet altijd de laatste parameter in de handtekening van de MethodNameAsync-methode zijn.Als uw klasse de Overbelasting van MethodNameAsync definieert die een parameter voor de objectwaarde of taak-id gebruikt, moet u de levensduur van de bewerking bijhouden met die taak-id en moet u deze weer in de voltooiingshandler opgeven. Er zijn helperklassen beschikbaar om u te helpen. Zie How to: Implement a Component That Supports the Event-based Asynchronous Pattern voor meer informatie over gelijktijdigheidsbeheer.
Als uw klasse de MethodNameAsync-methode definieert zonder de statusparameter en deze geen ondersteuning biedt voor meerdere gelijktijdige aanroepen, moet u ervoor zorgen dat elke poging om MethodNameAsync aan te roepen voordat de voorafgaande Aanroep van MethodNameAsync is voltooid, een InvalidOperationExceptionopheft.
Over het algemeen moet u geen uitzondering genereren als de MethodNameAsync-methode zonder de
userSuppliedState
parameter meerdere keren wordt aangeroepen, zodat er meerdere openstaande bewerkingen zijn. U kunt een uitzondering genereren wanneer uw klasse deze situatie expliciet niet kan afhandelen, maar ervan uitgaan dat ontwikkelaars deze meerdere niet-te onderscheiden callbacks kunnen verwerken
Toegang tot resultaten
Als er een fout is opgetreden tijdens de uitvoering van de asynchrone bewerking, mogen de resultaten niet toegankelijk zijn. Zorg ervoor dat toegang tot een eigenschap in de AsyncCompletedEventArgs eigenschap wanneer Error de uitzondering waarnaar wordt verwezen Errorniet
null
wordt gegenereerd. De AsyncCompletedEventArgs klasse biedt hiervoor de RaiseExceptionIfNecessary methode.Zorg ervoor dat elke poging om toegang te krijgen tot het resultaat een melding krijgt InvalidOperationException dat de bewerking is geannuleerd. Gebruik de AsyncCompletedEventArgs.RaiseExceptionIfNecessary methode om deze verificatie uit te voeren.
Voortgangsrapportage
Ondersteuning voor voortgangsrapportage, indien mogelijk. Hierdoor kunnen ontwikkelaars een betere gebruikerservaring voor toepassingen bieden wanneer ze uw klas gebruiken.
Als u een ProgressChanged- of MethodNameProgressChanged-gebeurtenis implementeert, moet u ervoor zorgen dat er geen dergelijke gebeurtenissen zijn gegenereerd voor een bepaalde asynchrone bewerking nadat de gebeurtenis MethodNameCompleted van die bewerking is gegenereerd.
Als de standaard wordt ingevuld, moet u ervoor zorgen dat de ProgressPercentage standaard ProgressChangedEventArgs altijd als percentage kan worden geïnterpreteerd. Het percentage hoeft niet nauwkeurig te zijn, maar moet een percentage vertegenwoordigen. Als uw metrische voortgangsrapportage iets anders moet zijn dan een percentage, moet u een klasse afleiden uit de ProgressChangedEventArgs klas en bij 0 vertrekken ProgressPercentage . Vermijd het gebruik van een andere metrische rapportagegegevens dan een percentage.
Zorg ervoor dat de
ProgressChanged
gebeurtenis wordt gegenereerd op de juiste thread en op het juiste moment in de levenscyclus van de toepassing. Zie de sectie Threading en Contexten voor meer informatie.
IsBusy-implementatie
Maak geen
IsBusy
eigenschap beschikbaar als uw klasse meerdere gelijktijdige aanroepen ondersteunt. Xml-webserviceproxy's maken bijvoorbeeld geen eigenschap beschikbaarIsBusy
omdat ze meerdere gelijktijdige aanroepen van asynchrone methoden ondersteunen.De
IsBusy
eigenschap moet worden geretourneerdtrue
nadat de MethodNameAsync-methode is aangeroepen en voordat de gebeurtenis MethodNameCompleted is gegenereerd. Anders moet deze worden geretourneerdfalse
. De BackgroundWorker en WebClient onderdelen zijn voorbeelden van klassen die eenIsBusy
eigenschap beschikbaar maken.
Opzegging
Annulering van ondersteuning, indien mogelijk. Hierdoor kunnen ontwikkelaars een betere gebruikerservaring voor toepassingen bieden wanneer ze uw klas gebruiken.
Stel in het geval van annulering de Cancelled vlag in het AsyncCompletedEventArgs object in.
Zorg ervoor dat elke poging om toegang te krijgen tot het resultaat een melding krijgt InvalidOperationException dat de bewerking is geannuleerd. Gebruik de AsyncCompletedEventArgs.RaiseExceptionIfNecessary methode om deze verificatie uit te voeren.
Zorg ervoor dat aanroepen naar een annuleringsmethode altijd correct worden geretourneerd en nooit een uitzondering genereren. Over het algemeen wordt een klant niet op de hoogte gesteld van de vraag of een bewerking op enig moment daadwerkelijk kan worden geannuleerd en wordt niet op de hoogte gesteld van of een eerder uitgegeven annulering is geslaagd. De toepassing krijgt echter altijd een melding wanneer een annulering is geslaagd, omdat de toepassing deelneemt aan de voltooiingsstatus.
De gebeurtenis MethodNameCompleted opheffen wanneer de bewerking wordt geannuleerd.
Fouten en uitzonderingen
- Neem eventuele uitzonderingen op die optreden in de asynchrone bewerking en stel de waarde van de AsyncCompletedEventArgs.Error eigenschap in op die uitzondering.
Threading en contexten
Voor de juiste werking van uw klasse is het essentieel dat de gebeurtenis-handlers van de client worden aangeroepen op de juiste thread of context voor het opgegeven toepassingsmodel, waaronder ASP.NET- en Windows Forms-toepassingen. Er worden twee belangrijke helperklassen gegeven om ervoor te zorgen dat uw asynchrone klasse zich correct gedraagt onder elk toepassingsmodel: AsyncOperation en AsyncOperationManager.
AsyncOperationManager biedt één methode, CreateOperationdie een AsyncOperationretourneert. De aanroepen van de MethodNameAsync-methode en uw klasse gebruikt de geretourneerde AsyncOperation methode om de levensduur van de asynchrone taak bij te CreateOperation houden.
Als u de voortgang, incrementele resultaten en voltooiing aan de client wilt rapporteren, roept u de Post en OperationCompleted methoden op de AsyncOperationclient aan. AsyncOperation is verantwoordelijk voor het marshallen van aanroepen naar de gebeurtenis-handlers van de client naar de juiste thread of context.
Notitie
U kunt deze regels omzeilen als u expliciet het beleid van het toepassingsmodel wilt toepassen, maar nog steeds profiteren van de andere voordelen van het gebruik van het Asynchrone patroon op basis van gebeurtenissen. U wilt bijvoorbeeld dat een klasse die in Windows Forms werkt, gratis threads bevat. U kunt een gratis threaded-klasse maken, zolang ontwikkelaars de impliciete beperkingen begrijpen. Consoletoepassingen synchroniseren de uitvoering van Post aanroepen niet. Dit kan ertoe leiden dat ProgressChanged
gebeurtenissen niet op volgorde worden gegenereerd. Als u de uitvoering van Post aanroepen wilt serialiseren, implementeert en installeert u een System.Threading.SynchronizationContext klasse.
Zie How to: Implement a Component That Supports the Event Based Asynchronous Pattern (Een onderdeel implementeren dat het Asynchrone patroon op basis van gebeurtenissen ondersteunt) voor meer informatie over het gebruik AsyncOperation en AsyncOperationManager inschakelen van asynchrone bewerkingen.
Richtlijnen
In het ideale geval moet elke methode-aanroep onafhankelijk zijn van anderen. Vermijd het koppelen van aanroepen met gedeelde resources. Als resources moeten worden gedeeld tussen aanroepen, moet u een correct synchronisatiemechanisme opgeven in uw implementatie.
Ontwerpen waarvoor de client synchronisatie moet implementeren, worden afgeraden. U kunt bijvoorbeeld een asynchrone methode hebben die een globaal statisch object als parameter ontvangt; meerdere gelijktijdige aanroepen van een dergelijke methode kunnen leiden tot beschadiging van gegevens of impasses.
Als u een methode implementeert met de overbelasting met meerdere aanroepen (
userState
in de handtekening), moet uw klasse een verzameling gebruikersstatussen of taak-id's en de bijbehorende in behandeling zijnde bewerkingen beheren. Deze verzameling moet worden beveiligd metlock
regio's, omdat de verschillende aanroepen objecten in de verzameling toevoegen en verwijderenuserState
.Overweeg waar mogelijk en passend klassen opnieuw te gebruiken
CompletedEventArgs
. In dit geval is de naamgeving niet consistent met de naam van de methode, omdat een bepaalde gemachtigde en EventArgs het type niet zijn gekoppeld aan één methode. Het is echter nooit acceptabel om ontwikkelaars te dwingen de waarde te casten die is opgehaald uit een eigenschap op de EventArgs eigenschap.Als u een klasse maakt die is afgeleid van Component, moet u uw eigen SynchronizationContext klasse niet implementeren en installeren. Toepassingsmodellen, geen onderdelen, bepalen het SynchronizationContext gebruikte model.
Wanneer u multithreading van elk soort gebruikt, kunt u zich mogelijk blootstellen aan zeer ernstige en complexe bugs. Zie Aanbevolen procedures voor beheerde threading voordat u een oplossing implementeert die gebruikmaakt van multithreading.
Zie ook
- AsyncOperation
- AsyncOperationManager
- AsyncCompletedEventArgs
- ProgressChangedEventArgs
- BackgroundWorker
- Het Asynchrone patroon op basis van gebeurtenissen implementeren
- Asynchroon patroon (EAP) op basis van gebeurtenissen
- Bepalen wanneer het Asynchrone patroon op basis van gebeurtenissen moet worden geïmplementeerd
- Aanbevolen procedures voor het implementeren van het Asynchrone patroon op basis van gebeurtenissen
- Procedure: Onderdelen gebruiken die ondersteuning bieden voor het Asynchrone patroon op basis van gebeurtenissen
- Procedure: Een onderdeel implementeren dat ondersteuning biedt voor het Asynchrone patroon op basis van gebeurtenissen