Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il modello asincrono basato su eventi offre un modo efficace per esporre il comportamento asincrono nelle classi, con semantica familiare di eventi e delegati. Per implementare il modello asincrono basato su eventi, è necessario seguire alcuni requisiti comportamentali specifici. Le sezioni seguenti descrivono i requisiti e le linee guida da considerare quando si implementa una classe che segue il modello asincrono basato su eventi.
Per una panoramica, vedere Implementazione del modello asincrono basato su eventi.
Garanzie comportamentali obbligatorie
Se si implementa il modello asincrono basato su eventi, è necessario fornire una serie di garanzie per garantire che la classe si comporti correttamente e che i client della classe possano basarsi su tale comportamento.
Completamento
Richiamare sempre il gestore dell'evento MethodNameCompleted quando si ha esito positivo, un errore o un annullamento. Le applicazioni non devono mai riscontrare una situazione in cui rimangono inattive e il completamento non si verifica mai. Un'eccezione a questa regola è se l'operazione asincrona stessa è progettata in modo che non venga mai completata.
Evento completato ed EventArgs
Per ogni metodo Async MethodName separato, applicare i requisiti di progettazione seguenti:
Definire un evento MethodNameCompleted nella stessa classe del metodo .
Definire una EventArgs classe e un delegato a corredo per l'evento MethodNameCompleted che deriva dalla AsyncCompletedEventArgs classe . Il nome predefinito della classe deve essere del formato NomeMetodoCompletedEventArgs.
Assicurarsi che la EventArgs classe sia specifica per i valori restituiti del metodo MethodName . Quando si usa la EventArgs classe , è consigliabile non richiedere mai agli sviluppatori di eseguire il cast del risultato.
L'esempio di codice seguente mostra rispettivamente un'implementazione valida e non valida di questo requisito di progettazione.
// 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);
}
Non definire una EventArgs classe per la restituzione di metodi che restituiscono
void. Usare invece un'istanza della AsyncCompletedEventArgs classe .Assicurati di attivare sempre l'evento MethodNameCompleted. Questo evento deve essere generato al completamento corretto, in caso di errore o in caso di annullamento. Le applicazioni non devono mai riscontrare una situazione in cui rimangono inattive e il completamento non si verifica mai.
Assicurarsi di intercettare eventuali eccezioni che si verificano nell'operazione asincrona e assegnare l'eccezione intercettata alla Error proprietà .
Se si è verificato un errore durante il completamento dell'attività, i risultati non devono essere accessibili. Quando la proprietà Error non è
null, accertarsi che l'accesso a qualsiasi proprietà nella struttura EventArgs generi un'eccezione. Usare il RaiseExceptionIfNecessary metodo per eseguire questa verifica.Considerare un timeout come errore. Quando si verifica un timeout, generare l'evento MethodNameCompleted e assegnare un oggetto TimeoutException alla proprietà Error.
Se la classe supporta più chiamate simultanee, verificare che l'evento MethodNameCompleted contenga l'oggetto appropriato
userSuppliedState.Assicurarsi che l'evento MethodNameCompleted venga generato nel thread appropriato e nel momento appropriato nel ciclo di vita dell'applicazione. Per altre informazioni, vedere la sezione Threading and Contexts.
Esecuzione simultanea di operazioni
Se la tua classe supporta più invocazioni simultanee, consentono allo sviluppatore di tenere traccia di ogni invocazione separatamente definendo l'overload MethodNameAsync che accetta un parametro di stato separatamente con valori di oggetto o un ID attività, denominato
userSuppliedState. Questo parametro deve essere sempre l'ultimo parametro nella firma del metodo Async MethodName.Se la tua classe definisce l'overload MethodNameAsync che accetta un parametro di stato con valori di oggetto o ID di task, assicurati di tenere traccia della durata dell'operazione con quell'ID di task e assicurati di fornirlo nuovamente nel gestore di completamento. Sono disponibili classi helper per facilitare l'assistenza. Per altre informazioni sulla gestione della concorrenza, vedere Procedura: Implementare un componente che supporta il modello asincrono basato su eventi.
Se la classe definisce il metodo MethodNameAsync senza il parametro state e non supporta più chiamate simultanee, assicurarsi che qualsiasi tentativo di richiamare MethodNameAsync prima che la chiamata asincronanomeMetodo precedente abbia completato genera un oggetto InvalidOperationException.
In generale, non generare un'eccezione se il metodo NomeMetodoAsync senza il parametro
userSuppliedStateviene richiamato più volte, in modo che ci siano più operazioni in sospeso. È possibile generare un'eccezione quando la classe non è in grado di gestire in modo esplicito tale situazione, ma si presuppone che gli sviluppatori possano gestire questi callback multipli indistinguibili.
Accesso ai risultati
Se si è verificato un errore durante l'esecuzione dell'operazione asincrona, i risultati non devono essere accessibili. Assicurarsi che l'accesso a qualsiasi proprietà in AsyncCompletedEventArgs quando Error non è
nullprovoca l'eccezione menzionata da Error. La AsyncCompletedEventArgs classe fornisce il RaiseExceptionIfNecessary metodo a questo scopo.Assicurarsi che qualsiasi tentativo di accesso al risultato generi un InvalidOperationException messaggio che informa che l'operazione è stata annullata. Usare il AsyncCompletedEventArgs.RaiseExceptionIfNecessary metodo per eseguire questa verifica.
Relazioni sullo stato di avanzamento
Supportare la creazione di report sullo stato di avanzamento, se possibile. Ciò consente agli sviluppatori di offrire un'esperienza utente dell'applicazione migliore quando usano la classe.
Se si implementa un evento ProgressChanged o MethodNameProgressChanged , assicurarsi che non siano generati eventi di questo tipo per una determinata operazione asincrona dopo che è stato generato l'evento MethodNameCompleted dell'operazione.
Se lo standard ProgressChangedEventArgs viene popolato, assicurarsi che ProgressPercentage possa sempre essere interpretato come percentuale. La percentuale non deve essere accurata, ma deve rappresentare una percentuale. Se la metrica relativa ai report sullo stato di avanzamento deve essere diversa da una percentuale, derivare una classe dalla ProgressChangedEventArgs classe e lasciare ProgressPercentage 0. Evitare di usare una metrica di report diversa da una percentuale.
Assicurarsi che l'evento
ProgressChangedvenga generato nel thread appropriato e nel momento appropriato nel ciclo di vita dell'applicazione. Per altre informazioni, vedere la sezione Threading and Contexts.
Implementazione di IsBusy
Non esporre una
IsBusyproprietà se la classe supporta più chiamate simultanee. Ad esempio, i proxy del servizio Web XML non espongono unaIsBusyproprietà perché supportano più chiamate simultanee di metodi asincroni.La
IsBusyproprietà deve restituiretruedopo che è stato chiamato il metodo MethodNameAsync e prima che sia stato generato l'evento MethodNameCompleted . In caso contrario, deve restituirefalse. I BackgroundWorker componenti e WebClient sono esempi di classi che espongono unaIsBusyproprietà.
Annullamento
Supporto dell'annullamento, se possibile. Ciò consente agli sviluppatori di offrire un'esperienza utente dell'applicazione migliore quando usano la classe.
In caso di annullamento, impostare il Cancelled flag nell'oggetto AsyncCompletedEventArgs .
Assicurarsi che qualsiasi tentativo di accesso al risultato generi un InvalidOperationException messaggio che informa che l'operazione è stata annullata. Usare il AsyncCompletedEventArgs.RaiseExceptionIfNecessary metodo per eseguire questa verifica.
Assicurarsi che le chiamate a un metodo di annullamento vengano sempre restituite correttamente e non generino mai un'eccezione. In generale, un client non riceve una notifica relativa all'annullamento di un'operazione in un determinato momento e non riceve una notifica relativa all'esito positivo di un annullamento rilasciato in precedenza. Tuttavia, all'applicazione verrà sempre inviata una notifica quando un annullamento ha avuto esito positivo, perché l'applicazione partecipa allo stato di completamento.
Generare l'evento MethodNameCompleted quando l'operazione viene annullata.
Errori ed eccezioni
- Intercettare eventuali eccezioni che si verificano nell'operazione asincrona e impostare il valore della AsyncCompletedEventArgs.Error proprietà su tale eccezione.
Threading e contesti
Per il corretto funzionamento della classe, è fondamentale che i gestori eventi del client vengano richiamati nel thread o nel contesto appropriato per il modello di applicazione specificato, incluse le applicazioni ASP.NET e Windows Form. Vengono fornite due importanti classi helper per garantire che la classe asincrona si comporti correttamente in qualsiasi modello di applicazione: AsyncOperation e AsyncOperationManager.
AsyncOperationManager fornisce un metodo, CreateOperation, che restituisce un oggetto AsyncOperation. Il metodo MethodNameAsync effettua la chiamata CreateOperation e la classe utilizza il AsyncOperation restituito per tenere traccia della durata dell'attività asincrona.
Per segnalare lo stato di avanzamento, i risultati incrementali e il completamento al client, chiamare i metodi Post e OperationCompleted su AsyncOperation. AsyncOperation è responsabile del marshalling delle chiamate ai gestori degli eventi del client al thread o al contesto appropriato.
Annotazioni
È possibile aggirare queste regole se si vuole esplicitamente andare contro la politica del modello di applicazione, ma continuare a beneficiare degli altri vantaggi derivanti dall'uso del modello asincrono basato su eventi. Ad esempio, potrebbe essere necessario che una classe operante in Windows Forms sia senza vincoli di threading. È possibile creare una classe a thread libero, purché gli sviluppatori comprendano le restrizioni implicite. Le applicazioni console non sincronizzano l'esecuzione delle Post chiamate. Questo può causare che gli eventi ProgressChanged vengano generati fuori ordine. Se si vuole avere l'esecuzione serializzata delle Post chiamate, implementare e installare una System.Threading.SynchronizationContext classe .
Per ulteriori informazioni sull'uso di AsyncOperation e AsyncOperationManager per abilitare le operazioni asincrone, vedere Procedura: Implementare un componente che supporta il modello asincrono basato su eventi.
Istruzioni
Idealmente, ogni chiamata al metodo deve essere indipendente da altre. È consigliabile evitare l'accoppiamento delle chiamate con le risorse condivise. Se le risorse devono essere condivise tra le chiamate, sarà necessario fornire un meccanismo di sincronizzazione appropriato nell'implementazione.
Le progettazioni che richiedono al client di implementare la sincronizzazione sono sconsigliate. Ad esempio, è possibile avere un metodo asincrono che riceve un oggetto statico globale come parametro; più chiamate simultanee di tale metodo possono causare il danneggiamento dei dati o i deadlock.
Quando si implementa un metodo con sovraccarico a chiamata multipla (
userStatenella firma), la classe avrà bisogno di gestire una raccolta di stati utente o ID attività e le corrispondenti operazioni in sospeso. Questa raccolta deve essere protetta conlockaree, perché le varie chiamate aggiungono e rimuovonouserStateoggetti nella raccolta.Valutare la possibilità di riutilizzare
CompletedEventArgsle classi ove possibile e appropriato. In questo caso, la denominazione non è coerente con il nome del metodo, perché un delegato e EventArgs un tipo specificati non sono associati a un singolo metodo. Tuttavia, forzare gli sviluppatori a effettuare il cast del valore recuperato da una proprietà sul EventArgs non è mai accettabile.Se si crea una classe che deriva da Component, non implementare e installare la propria SynchronizationContext classe. I modelli di applicazione, non i componenti, controllano l'oggetto SynchronizationContext usato.
Quando si usa il multithreading di qualsiasi tipo, è possibile esporre se stessi a bug molto gravi e complessi. Prima di implementare qualsiasi soluzione che usa il multithreading, vedere Procedure consigliate per il threading gestito.
Vedere anche
- AsyncOperation
- AsyncOperationManager
- AsyncCompletedEventArgs
- ProgressChangedEventArgs
- BackgroundWorker
- Implementazione del modello asincrono basato su eventi
- Event-based Asynchronous Pattern (EAP) (Modello asincrono basato su eventi, EAP)
- Decidere quando implementare il modello asincrono basato su eventi
- Procedure consigliate per l'implementazione del modello asincrono basato su eventi
- Procedura: Usare componenti che supportano il modello asincrono basato su eventi
- Procedura: Implementare un componente che supporta il modello asincrono basato su eventi