Implementazione del modello asincrono basato su eventiImplementing the Event-based Asynchronous Pattern

In caso di scrittura di una classe con alcune operazioni che possono causare ritardi notevoli, è consigliabile assegnare la funzionalità asincrona implementando Cenni preliminari sul modello asincrono basato su eventi.If you are writing a class with some operations that may incur noticeable delays, consider giving it asynchronous functionality by implementing Event-based Asynchronous Pattern Overview.

Il modello asincrono basato su eventi offre un modo standardizzato per aggiungere funzionalità asincrone a una classe.The Event-based Asynchronous Pattern provides a standardized way to package a class that has asynchronous features. Se implementata con classi helper come AsyncOperationManager, la classe funzionerà con qualsiasi modello di applicazione, tra cui ASP.NETASP.NET, applicazioni console e Windows Forms Application.If implemented with helper classes like AsyncOperationManager, your class will work correctly under any application model, including ASP.NETASP.NET, Console applications, and Windows Forms applications.

Per un esempio che implementa il modello asincrono basato su eventi, vedere Procedura: Implementare un componente che supporta il modello asincrono basato su eventi.For an example that implements the Event-based Asynchronous Pattern, see How to: Implement a Component That Supports the Event-based Asynchronous Pattern.

Per operazioni asincrone semplici, può risultare idoneo il componente BackgroundWorker.For simple asynchronous operations, you may find the BackgroundWorker component suitable. Per altre informazioni su BackgroundWorker, vedere Procedura: eseguire un'operazione in background.For more information about BackgroundWorker, see How to: Run an Operation in the Background.

L'elenco seguente descrive le funzionalità del modello asincrono basato su eventi affrontate in questo argomento.The following list describes the features of the Event-based Asynchronous Pattern discussed in this topic.

  • Opportunità per implementare il modello asincrono basato su eventiOpportunities for Implementing the Event-based Asynchronous Pattern

  • Denominazione di metodi asincroniNaming Asynchronous Methods

  • Supporto facoltativo dell'annullamentoOptionally Support Cancellation

  • Supporto facoltativo della proprietà IsBusyOptionally Support the IsBusy Property

  • Supporto facoltativo per la generazione di report sullo stato di avanzamentoOptionally Provide Support for Progress Reporting

  • Supporto facoltativo per la restituzione di risultati incrementaliOptionally Provide Support for Returning Incremental Results

  • Gestione dei parametri Out e Ref nei metodiHandling Out and Ref Parameters in Methods

Opportunità per implementare il modello asincrono basato su eventiOpportunities for Implementing the Event-based Asynchronous Pattern

Valutare l'implementazione del modello asincrono basato su eventi quando:Consider implementing the Event-based Asynchronous Pattern when:

  • I client della classe non richiedono che siano disponibili oggetti WaitHandle e IAsyncResult per le operazioni asincrone, quindi il polling e il metodo WaitAll o WaitAny devono essere compilati dal client.Clients of your class do not need WaitHandle and IAsyncResult objects available for asynchronous operations, meaning that polling and WaitAll or WaitAny will need to be built up by the client.

  • Si desidera che le operazioni asincrone vengano gestite dal client con il modello noto di evento/delegato.You want asynchronous operations to be managed by the client with the familiar event/delegate model.

Qualsiasi operazione è un candidato per un'implementazione asincrona, ma è opportuno considerare quelle con lunghe latenze previste.Any operation is a candidate for an asynchronous implementation, but those you expect to incur long latencies should be considered. Sono particolarmente indicate le operazioni in cui i client chiamano un metodo e ricevono una notifica al completamento, senza richiedere ulteriori interventi.Especially appropriate are operations in which clients call a method and are notified on completion, with no further intervention required. Rientrano in questa condizione anche le operazioni con esecuzione continua,che inviano notifiche periodiche ai client sullo stato di avanzamento, sui risultati incrementali o sulle modifiche di stato.Also appropriate are operations which run continuously, periodically notifying clients of progress, incremental results, or state changes.

Per altre informazioni sui casi in cui supportare il modello asincrono basato su eventi, vedere Quando implementare il modello asincrono basato su eventi.For more information on deciding when to support the Event-based Asynchronous Pattern, see Deciding When to Implement the Event-based Asynchronous Pattern.

Denominazione di metodi asincroniNaming Asynchronous Methods

Per ogni metodo MethodName sincrono per il quale si desidera specificare una controparte asincrona:For each synchronous method MethodName for which you want to provide an asynchronous counterpart:

Definire un metodo MethodNameAsync che:Define a MethodNameAsync method that:

  • Restituisce void.Returns void.

  • Accetta gli stessi parametri del metodo MethodName.Takes the same parameters as the MethodName method.

  • Accetta più chiamate.Accepts multiple invocations.

Facoltativamente, definire un overload di MethodNameAsync, identico a MethodNameAsync, ma con un parametro con valore di oggetto aggiuntivo denominato userState.Optionally define a MethodNameAsync overload, identical to MethodNameAsync, but with an additional object-valued parameter called userState. Seguire questa procedura se si intende gestire più chiamate simultanee del metodo, nel qual caso il valore userState verrà recapitato nuovamente a tutti i gestori eventi per distinguere le chiamate del metodo.Do this if you're prepared to manage multiple concurrent invocations of your method, in which case the userState value will be delivered back to all event handlers to distinguish invocations of the method. È anche possibile scegliere questa opzione come posizione in cui archiviare lo stato utente per un successivo recupero.You may also choose to do this simply as a place to store user state for later retrieval.

Per ogni firma del metodo MethodNameAsync distinta:For each separate MethodNameAsync method signature:

  1. Definire l'evento seguente nella stessa classe del metodo:Define the following event in the same class as the method:

    Public Event MethodNameCompleted As MethodNameCompletedEventHandler  
    
    public event MethodNameCompletedEventHandler MethodNameCompleted;  
    
  2. Definire il delegato seguente e AsyncCompletedEventArgs.Define the following delegate and AsyncCompletedEventArgs. che verranno probabilmente definiti all'esterno della classe, ma nello stesso spazio dei nomi.These will likely be defined outside of the class itself, but in the same namespace.

    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; }  
    }  
    
    • Verificare che la classe MethodNameCompletedEventArgs esponga i relativi membri come proprietà di sola lettura e non come campi, dal momento che questi ultimi non consentono il data binding.Ensure that the MethodNameCompletedEventArgs class exposes its members as read-only properties, and not fields, as fields prevent data binding.

    • Non definire alcuna classe derivata da AsyncCompletedEventArgs per i metodi che non producono risultati.Do not define any AsyncCompletedEventArgs-derived classes for methods that do not produce results. Usare semplicemente un'istanza di AsyncCompletedEventArgs.Simply use an instance of AsyncCompletedEventArgs itself.

      Nota

      È perfettamente accettabile, quando possibile e appropriato, riutilizzare il delegato e i tipi AsyncCompletedEventArgs.It is perfectly acceptable, when feasible and appropriate, to reuse delegate and AsyncCompletedEventArgs types. In questo caso, la denominazione non sarà coerente con il nome del metodo, perché un delegato e un oggetto AsyncCompletedEventArgs specifici non saranno associati a un singolo metodo.In this case, the naming will not be as consistent with the method name, since a given delegate and AsyncCompletedEventArgs won't be tied to a single method.

Supporto facoltativo dell'annullamentoOptionally Support Cancellation

Se la classe supporta l'annullamento delle operazioni asincrone, l'annullamento dovrebbe essere esposto al client come descritto di seguito.If your class will support canceling asynchronous operations, cancellation should be exposed to the client as described below. Si noti che è necessario raggiungere due decisioni prima di definire il supporto dell'annullamento:Note that there are two decision points that need to be reached before defining your cancellation support:

  • La classe, incluse eventuali aggiunte future previste, include una sola operazione asincrona che supporta l'annullamento?Does your class, including future anticipated additions to it, have only one asynchronous operation that supports cancellation?

  • Le operazioni asincrone che supportano l'annullamento supportano più operazioni in sospeso?Can the asynchronous operations that support cancellation support multiple pending operations? In altre parole, il metodo MethodNameAsync accetta un parametro userState e consente più chiamate prima di attendere il completamento di una di esse?That is, does the MethodNameAsync method take a userState parameter, and does it allow multiple invocations before waiting for any to finish?

Usare le risposte a queste due domande nella tabella seguente per determinare la firma per il metodo di annullamento scelto.Use the answers to these two questions in the table below to determine what the signature for your cancellation method should be.

Visual BasicVisual Basic

Più operazioni simultanee supportateMultiple Simultaneous Operations Supported Una sola operazione alla voltaOnly One Operation at a Time
Una operazione asincrona nell'intera classeOne Async Operation in entire class Sub MethodNameAsyncCancel(ByVal userState As Object) Sub MethodNameAsyncCancel()
Più operazioni asincrone nella classeMultiple Async Operations in class Sub CancelAsync(ByVal userState As Object) Sub CancelAsync()

C#C#

Più operazioni simultanee supportateMultiple Simultaneous Operations Supported Una sola operazione alla voltaOnly One Operation at a Time
Una operazione asincrona nell'intera classeOne Async Operation in entire class void MethodNameAsyncCancel(object userState); void MethodNameAsyncCancel();
Più operazioni asincrone nella classeMultiple Async Operations in class void CancelAsync(object userState); void CancelAsync();

Se si definisce il metodo CancelAsync(object userState), i client devono scegliere con cautela i valori di stato per permettere la distinzione tra tutti i metodi asincroni chiamati sull'oggetto e non solo tra tutte le chiamate di un singolo metodo asincrono.If you define the CancelAsync(object userState) method, clients must be careful when choosing their state values to make them capable of distinguishing among all asynchronous methods invoked on the object, and not just between all invocations of a single asynchronous method.

La decisione di assegnare alla versione della singola operazione asincrona il nome MethodNameAsyncCancel si basa sula capacità di individuare più facilmente il metodo in un ambiente di progettazione come IntelliSense di Visual Studio.The decision to name the single-async-operation version MethodNameAsyncCancel is based on being able to more easily discover the method in a design environment like Visual Studio's IntelliSense. Questo raggruppa i membri correlati e li distingue dagli altri membri che non hanno a che fare con funzionalità asincrone.This groups the related members and distinguishes them from other members that have nothing to do with asynchronous functionality. Se si prevede che potrebbero essere aggiunte altre operazioni asincrone nelle versioni successive, è preferibile definire CancelAsync.If you expect that there may be additional asynchronous operations added in subsequent versions, it is better to define CancelAsync.

Non definire più metodi della tabella precedente nella stessa classe.Do not define multiple methods from the table above in the same class. Non avrebbe senso e creerebbe confusione nell'interfaccia della classe con un numero eccessivo di metodi.That will not make sense, or it will clutter the class interface with a proliferation of methods.

Questi metodi vengono in genere restituiti immediatamente e l'esito dell'operazione di annullamento non è garantito.These methods typically will return immediately, and the operation may or may not actually cancel. Nel gestore dell'evento MethodNameCompleted l'oggetto MethodNameCompletedEventArgs contiene un campo Cancelled, che i client possono usare per determinare se si è verificato l'annullamento.In the event handler for the MethodNameCompleted event, the MethodNameCompletedEventArgs object contains a Cancelled field, which clients can use to determine whether the cancellation occurred.

Rispettare la semantica di annullamento descritta in Suggerimenti per l'implementazione del modello asincrono basato su eventi.Abide by the cancellation semantics described in Best Practices for Implementing the Event-based Asynchronous Pattern.

Supporto facoltativo della proprietà IsBusyOptionally Support the IsBusy Property

Se la classe non supporta più chiamate simultanee, è consigliabile esporre una proprietà IsBusy.If your class does not support multiple concurrent invocations, consider exposing an IsBusy property. In questo modo, gli sviluppatori possono stabilire se un metodoMethodNameAsync è in esecuzione senza intercettare un'eccezione generata dal metodo MethodNameAsync.This allows developers to determine whether a MethodNameAsync method is running without catching an exception from the MethodNameAsync method.

Rispettare la semantica di IsBusy descritta in Suggerimenti per l'implementazione del modello asincrono basato su eventi.Abide by the IsBusy semantics described in Best Practices for Implementing the Event-based Asynchronous Pattern.

Supporto facoltativo per la generazione di report sullo stato di avanzamentoOptionally Provide Support for Progress Reporting

È spesso utile che un'operazione asincrona generi un report sullo stato di avanzamento durante il funzionamento.It is frequently desirable for an asynchronous operation to report progress during its operation. Il modello asincrono basato su eventi offre linee guida a tale scopo.The Event-based Asynchronous Pattern provides a guideline for doing so.

  • Definire facoltativamente un evento che verrà generato dall'operazione asincrona e chiamato sul thread appropriato.Optionally define an event to be raised by the asynchronous operation and invoked on the appropriate thread. L'oggetto ProgressChangedEventArgs supporta un indicatore di stato con valori interi compresi tra 0 e 100.The ProgressChangedEventArgs object carries an integer-valued progress indicator that is expected to be between 0 and 100.

  • Denominare l'evento come indicato di seguito:Name this event as follows:

    • ProgressChanged se la classe dispone di più operazioni asincrone (o presumibilmente aumenterà per includere più operazioni asincrone nelle versioni future);ProgressChanged if the class has multiple asynchronous operations (or is expected to grow to include multiple asynchronous operations in future versions);

    • MethodNameProgressChanged se la classe include una singola operazione asincrona.MethodNameProgressChanged if the class has a single asynchronous operation.

    Questa scelta di denominazione è paragonabile a quella eseguita per il metodo di annullamento, come descritto nella sezione Supporto facoltativo dell'annullamento.This naming choice parallels that made for the cancellation method, as described in the Optionally Support Cancellation section.

Questo evento deve usare la firma del delegato ProgressChangedEventHandler e la classe ProgressChangedEventArgs.This event should use the ProgressChangedEventHandler delegate signature and the ProgressChangedEventArgs class. In alternativa, se è possibile fornire un indicatore di stato più specifico per il dominio (ad esempio, byte letti e byte totali per un'operazione di download), è consigliabile definire una classe derivata di ProgressChangedEventArgs.Alternatively, if a more domain-specific progress indicator can be provided (for instance, bytes read and total bytes for a download operation), then you should define a derived class of ProgressChangedEventArgs.

Si noti che per la classe è presente un solo evento ProgressChanged o MethodNameProgressChanged, indipendentemente dal numero di metodi asincroni supportati.Note that there is only one ProgressChanged or MethodNameProgressChanged event for the class, regardless of the number of asynchronous methods it supports. Per i client è previsto l'uso dell'oggetto userState passato ai metodi MethodNameAsync per distinguere tra aggiornamenti dello stato di avanzamento in più operazioni simultanee.Clients are expected to use the userState object that is passed to the MethodNameAsync methods to distinguish among progress updates on multiple concurrent operations.

In alcuni casi, più operazioni potrebbero supportare lo stato di avanzamento e restituire singolarmente un indicatore diverso.There may be situations in which multiple operations support progress and each returns a different indicator for progress. In questo caso, un singolo evento ProgressChanged non è appropriato ed è opportuno scegliere di supportare più eventi ProgressChanged.In this case, a single ProgressChanged event is not appropriate, and you may consider supporting multiple ProgressChanged events. In questo caso usare un modello di denominazione MethodNameProgressChanged per ogni metodo MethodNameAsync.In this case use a naming pattern of MethodNameProgressChanged for each MethodNameAsync method.

Rispettare la semantica della generazione di report sullo stato di avanzamento descritta in Suggerimenti per l'implementazione del modello asincrono basato su eventi.Abide by the progress-reporting semantics described Best Practices for Implementing the Event-based Asynchronous Pattern.

Supporto facoltativo per la restituzione di risultati incrementaliOptionally Provide Support for Returning Incremental Results

A volte un'operazione asincrona può restituire risultati incrementali prima del completamento.Sometimes an asynchronous operation can return incremental results prior to completion. Per supportare questo scenario sono disponibili numerose opzioni.There are a number of options that can be used to support this scenario. Di seguito sono riportati alcuni esempi.Some examples follow.

Classe con singola operazioneSingle-operation Class

Se la classe supporta solo una singola operazione asincrona e tale operazione è in grado di restituire risultati incrementali:If your class only supports a single asynchronous operation, and that operation is able to return incremental results, then:

  • Estendere il tipo ProgressChangedEventArgs per il supporto dei dati dei risultati incrementali e definire un evento MethodNameProgressChanged con i dati estesi.Extend the ProgressChangedEventArgs type to carry the incremental result data, and define a MethodNameProgressChanged event with this extended data.

  • Generare questo evento MethodNameProgressChanged in presenza di un risultato incrementale da segnalare.Raise this MethodNameProgressChanged event when there is an incremental result to report.

Questa soluzione si applica in modo specifico a una classe con singola operazione asincrona poiché non determina alcun problema se lo stesso evento si ripete per restituire gli stessi risultati incrementali in tutte le operazioni, come avviene con l'evento MethodNameProgressChanged.This solution applies specifically to a single-async-operation class because there is no problem with the same event occurring to return incremental results on "all operations", as the MethodNameProgressChanged event does.

Classe con più operazioni con risultati incrementali omogeneiMultiple-operation Class with Homogeneous Incremental Results

In questo caso, la classe supporta più metodi asincroni, ognuno dei quali è in grado di restituire risultati incrementali che avranno tutti lo stesso tipo di dati.In this case, your class supports multiple asynchronous methods, each capable of returning incremental results, and these incremental results all have the same type of data.

Seguire il modello descritto in precedenza per le classi con singola operazione, poiché la stessa struttura di EventArgs è applicabile a tutti i risultati incrementali.Follow the model described above for single-operation classes, as the same EventArgs structure will work for all incremental results. Definire un evento ProgressChanged invece di un evento MethodNameProgressChanged, dal momento che si applica a più metodi asincroni.Define a ProgressChanged event instead of a MethodNameProgressChanged event, since it applies to multiple asynchronous methods.

Classe con più operazioni con risultati incrementali eterogeneiMultiple-operation Class with Heterogeneous Incremental Results

Se la classe supporta più metodi asincroni, ognuno dei quali restituisce un tipo diverso di dati, è consigliabile:If your class supports multiple asynchronous methods, each returning a different type of data, you should:

  • Separare il report dei risultati incrementali dal report sullo stato di avanzamento.Separate your incremental result reporting from your progress reporting.

  • Definire un eventoMethodNameProgressChanged separato con l'oggetto EventArgs appropriato per ciascun metodo asincrono in modo da gestire i dati dei risultati incrementali del metodo.Define a separate MethodNameProgressChanged event with appropriate EventArgs for each asynchronous method to handle that method's incremental result data.

Chiamare il gestore eventi sul thread appropriato, come descritto in Suggerimenti per l'implementazione del modello asincrono basato su eventi.Invoke that event handler on the appropriate thread as described in Best Practices for Implementing the Event-based Asynchronous Pattern.

Gestione dei parametri Out e Ref nei metodiHandling Out and Ref Parameters in Methods

Sebbene l'uso di out e ref sia, in generale, sconsigliato in .NET Framework, ecco le regole da seguire quando sono presenti:Although the use of out and ref is, in general, discouraged in the .NET Framework, here are the rules to follow when they are present:

Dato un metodo MethodName sincrono:Given a synchronous method MethodName:

  • I parametri out di MethodName non devono far parte di MethodNameAsync. Devono invece far parte di MethodNameCompletedEventArgs, con lo stesso nome del relativo parametro equivalente in MethodName (a meno che non ci sia un nome più appropriato).out parameters to MethodName should not be part of MethodNameAsync. Instead, they should be part of MethodNameCompletedEventArgs with the same name as its parameter equivalent in MethodName (unless there is a more appropriate name).

  • I parametri ref di MethodName devono far parte di MethodNameAsync e di MethodNameCompletedEventArgs, con lo stesso nome del relativo parametro equivalente in MethodName (a meno che non ci sia un nome più appropriato).ref parameters to MethodName should appear as part of MethodNameAsync, and as part of MethodNameCompletedEventArgs with the same name as its parameter equivalent in MethodName (unless there is a more appropriate name).

Ad esempio, dato:For example, given:

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

Il metodo asincrono e la relativa classe AsyncCompletedEventArgs avranno un aspetto simile al seguente:Your asynchronous method and its AsyncCompletedEventArgs class would look like this:

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

Vedere ancheSee Also

ProgressChangedEventArgs
AsyncCompletedEventArgs
Procedura: Implementare un componente che supporta il modello asincrono basato su eventiHow to: Implement a Component That Supports the Event-based Asynchronous Pattern
Procedura: Eseguire un'operazione in backgroundHow to: Run an Operation in the Background
Procedura: Implementare un form che esegue un'operazione in backgroundHow to: Implement a Form That Uses a Background Operation
Quando implementare il modello asincrono basato su eventiDeciding When to Implement the Event-based Asynchronous Pattern
Programmazione multithreading con il modello asincrono basato su eventiMultithreaded Programming with the Event-based Asynchronous Pattern
Suggerimenti per l'implementazione del modello asincrono basato su eventiBest Practices for Implementing the Event-based Asynchronous Pattern