Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El patrón asincrónico basado en eventos ofrece una manera eficaz de exponer el comportamiento asincrónico en las clases, con la conocida semántica de eventos y delegados. Para implementar el patrón asincrónico basado en eventos, debe seguir algunos requisitos de comportamiento específicos. En las secciones siguientes se describen los requisitos y las directrices que debe tener en cuenta al implementar una clase que siga el patrón asincrónico basado en eventos.
Para obtener información general, consulte Implementación del patrón asincrónico basado en eventos.
Garantías de comportamiento requeridas
Si implementa el patrón asincrónico basado en eventos, debe proporcionar una serie de garantías para asegurarse de que la clase se comportará correctamente y los clientes de la clase pueden confiar en ese comportamiento.
Finalización
Invoque siempre el controlador de eventos MethodNameCompleted cuando haya completado correctamente, un error o una cancelación. Las aplicaciones nunca deben encontrarse con una situación en la que permanecen inactivos y la finalización nunca se produce. Una excepción a esta regla es si la propia operación asincrónica está diseñada para que nunca se complete.
Evento Completed y EventArgs
Para cada método MethodNameAsync independiente, aplique los siguientes requisitos de diseño:
Defina un evento MethodNameCompleted en la misma clase que el método .
Defina una clase y un EventArgs delegado complementario para el evento MethodNameCompleted que deriva de la AsyncCompletedEventArgs clase . El nombre de clase predeterminado debe ser del formulario MethodNameCompletedEventArgs.
Asegúrese de que la EventArgs clase es específica de los valores devueltos del método MethodName . Cuando use la clase EventArgs, nunca les pida a los desarrolladores que conviertan el resultado.
En el ejemplo de código siguiente se muestra una implementación correcta y incorrecta de este requisito de diseño, respectivamente.
// 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);
}
No defina una EventArgs clase para devolver métodos que devuelvan
void
. En su lugar, use una instancia de la AsyncCompletedEventArgs clase .Asegúrese de que siempre eleve el evento MethodNameCompleted. Este evento debe generarse cuando se produce una finalización correcta, un error o una cancelación. Las aplicaciones nunca deben encontrarse con una situación en la que permanecen inactivos y la finalización nunca se produce.
Asegúrese de detectar las excepciones que se producen en la operación asincrónica y asignar la excepción detectada a la Error propiedad .
Si se produjo un error al completar la tarea, los resultados no deberían ser accesibles. Cuando la propiedad Error no es
null
, asegúrese de que el acceso a cualquier propiedad dentro de la estructura EventArgs levante una excepción. Use el RaiseExceptionIfNecessary método para realizar esta comprobación.Cree un modelo de error para los agotamientos del tiempo de espera. Cuando se agote el tiempo de espera, genere el evento MethodNameCompleted y asigne TimeoutException a la propiedad Error.
Si la clase admite varias invocaciones simultáneas, asegúrese de que el evento MethodNameCompleted contiene el objeto adecuado
userSuppliedState
.Asegúrese de que el evento MethodNameCompleted se genera en el subproceso adecuado y en el momento adecuado en el ciclo de vida de la aplicación. Para obtener más información, vea la sección Subprocesos y contextos.
Ejecución simultánea de operaciones
Si la clase admite varias invocaciones simultáneas, habilite al desarrollador para realizar un seguimiento de cada invocación por separado mediante la definición de la sobrecarga asincrónicaMethodName que toma un parámetro de estado con valores de objeto o identificador de tarea, denominado
userSuppliedState
. Este parámetro siempre debe ser el último parámetro de la firma del método MethodNameAsync .Si su clase define la sobrecarga MethodNameAsync que toma un parámetro de estado con valor de objeto o un identificador de tarea, asegúrese de hacer un seguimiento de la duración de la operación con ese identificador de tarea y devolverlo al controlador de finalización. Hay clases auxiliares disponibles para ayudar. Para obtener más información sobre la administración de simultaneidad, vea Cómo: Implementar un componente que admita el patrón asincrónico basado en eventos.
Si su clase define el método MethodNameAsync sin el parámetro de estado y no admite múltiples invocaciones simultáneas, asegúrese de que cualquier intento de invocar MethodNameAsync antes de que se haya completado la invocación previa del método MethodNameAsync genere un error.InvalidOperationException
En general, no genere una excepción si el método MethodNameAsync sin el
userSuppliedState
parámetro se invoca varias veces para que haya varias operaciones pendientes. Puede generar una excepción si la clase no puede controlar esa situación de forma explícita, pero piense que los desarrolladores pueden gestionar varias devoluciones de llamadas indistinguibles.
Obtener acceso a los resultados
Si se produjo un error durante la ejecución de la operación asincrónica, los resultados no deberían ser accesibles. Asegúrese de que el acceso a cualquier propiedad de AsyncCompletedEventArgs cuando Error no sea
null
genera la excepción a la que hace Errorreferencia. La AsyncCompletedEventArgs clase proporciona el RaiseExceptionIfNecessary método para este propósito.Asegúrese de que cualquier intento de acceder al resultado genera un InvalidOperationException que indica que se canceló la operación. Use el AsyncCompletedEventArgs.RaiseExceptionIfNecessary método para realizar esta comprobación.
Informes de progreso
Apoyar los informes de progreso, si es posible. Esto permite a los desarrolladores proporcionar una mejor experiencia de usuario de la aplicación cuando usan su clase.
Si implementa un evento ProgressChanged o MethodNameProgressChanged , asegúrese de que no se generan estos eventos para una operación asincrónica determinada después de que se haya generado el evento MethodNameCompleted de esa operación.
Si se rellena el estándar ProgressChangedEventArgs , asegúrese de que ProgressPercentage siempre se puede interpretar como un porcentaje. No es necesario que el porcentaje sea preciso, pero debe representar un porcentaje. Si la métrica de informes de progreso debe ser algo distinto de un porcentaje, derive una clase de la ProgressChangedEventArgs clase y deje ProgressPercentage en 0. Evite usar una métrica de informes distinta de un porcentaje.
Asegúrese de que el evento
ProgressChanged
se genera en el hilo correcto y en el momento adecuado en el ciclo de vida de la aplicación. Para obtener más información, vea la sección Subprocesos y contextos.
Implementación de IsBusy
No exponga una
IsBusy
propiedad si la clase admite varias invocaciones simultáneas. Por ejemplo, los servidores proxy de servicio web XML no exponen unaIsBusy
propiedad porque admiten varias invocaciones simultáneas de métodos asincrónicos.La
IsBusy
propiedad debe devolversetrue
después de llamar al método MethodNameAsync y antes de que se haya generado el evento MethodNameCompleted . De lo contrario, debe devolverfalse
. Los BackgroundWorker componentes y WebClient son ejemplos de clases que exponen unaIsBusy
propiedad .
Cancelación
Si es posible, admita cancelación. Esto permite a los desarrolladores proporcionar una mejor experiencia de usuario de la aplicación cuando usan su clase.
En caso de cancelación, marque la bandera Cancelled en el objeto AsyncCompletedEventArgs.
Asegúrese de que cualquier intento de acceder al resultado genera un InvalidOperationException que indica que se canceló la operación. Use el AsyncCompletedEventArgs.RaiseExceptionIfNecessary método para realizar esta comprobación.
Asegúrese de que las llamadas a un método de cancelación siempre se devuelven correctamente y nunca generan una excepción. En general, un cliente no recibe una notificación sobre si una operación es realmente cancelable en un momento dado y no se notifica si una cancelación emitida anteriormente se ha realizado correctamente. No obstante, la aplicación siempre recibirá notificación cuando la cancelación tenga éxito, ya que la aplicación participa en el estado de finalización.
Genere el evento MethodNameCompleted cuando se cancele la operación.
Errores y excepciones
- Capture las excepciones que se produzcan en la operación asincrónica y establezca el valor de la AsyncCompletedEventArgs.Error propiedad en esa excepción.
Subprocesos y contextos
Para el funcionamiento correcto de la clase, es fundamental que los controladores de eventos del cliente se invoquen en el subproceso o contexto adecuados para el modelo de aplicación determinado, incluidas las aplicaciones de ASP.NET y Windows Forms. Se proporcionan dos clases auxiliares importantes para asegurarse de que la clase asincrónica se comporta correctamente en cualquier modelo de aplicación: AsyncOperation y AsyncOperationManager.
AsyncOperationManager proporciona un método , , CreateOperationque devuelve un AsyncOperation. Su método MethodNameAsync llama a CreateOperation y su clase utiliza el valor devuelto AsyncOperation para realizar un seguimiento de la duración de la tarea asincrónica.
Para notificar el progreso, los resultados incrementales y la finalización al cliente, llame a los métodos Post y OperationCompleted en el AsyncOperation. AsyncOperation es responsable de coordinar las llamadas a los controladores de eventos del cliente hacia el hilo o contexto adecuado.
Nota:
Puede omitir estas reglas si desea ir explícitamente en contra de la política del modelo de aplicación, pero seguir beneficiándose de las demás ventajas de usar el patrón asincrónico basado en eventos. Por ejemplo, es posible que desee que una clase que opera en Windows Forms sea de subproceso libre. Puede crear una clase de subproceso libre si los desarrolladores entienden las restricciones implícitas. Las aplicaciones de consola no sincronizan la ejecución de Post llamadas. Esto puede provocar que se generen eventos ProgressChanged
fuera de lugar. Si desea haber serializado la ejecución de Post llamadas, implemente e instale una System.Threading.SynchronizationContext clase.
Para obtener más información sobre el uso de AsyncOperation y AsyncOperationManager para habilitar tus operaciones asincrónicas, consulta Cómo implementar un componente que soporte el patrón asincrónico basado en eventos.
Directrices
Lo ideal es que cada invocación de método sea independiente de otras. Se debería evitar acoplar invocaciones con recursos compartidos. Si los recursos se van a compartir entre invocaciones, deberá proporcionar un mecanismo de sincronización adecuado en la implementación.
Los diseños que requieren que el cliente implemente la sincronización no se recomienda. Por ejemplo, podría tener un método asincrónico que reciba un objeto estático global como parámetro; varias invocaciones simultáneas de este método podrían provocar daños en los datos o interbloqueos.
Si implementa un método con la sobrecarga de invocación múltiple (
userState
en la firma), la clase deberá administrar una colección de estados de usuario o identificadores de tarea y sus operaciones pendientes correspondientes. Esta colección debe protegerse conlock
regiones, ya que las distintas invocaciones agregan y quitanuserState
objetos de la colección.Considere reutilizar las clases
CompletedEventArgs
donde sea factible y adecuado. En este caso, la nomenclatura no es coherente con el nombre del método, ya que un delegado y EventArgs tipo determinado no están vinculados a un único método. Sin embargo, jamás se puede forzar a los desarrolladores a que conviertan el valor recuperado de una propiedad en la clase EventArgs.Si va a crear una clase que derive de Component, no implemente e instale su propia SynchronizationContext clase. Los modelos de aplicación, no los componentes, controlan el SynchronizationContext que se usa.
Al usar multithreading de cualquier tipo, puede exponerse a errores muy graves y complejos. Antes de implementar cualquier solución que utilice el subprocesamiento múltiple, consulte Procedimientos recomendados para el subprocesamiento administrado.
Consulte también
- AsyncOperation
- AsyncOperationManager
- AsyncCompletedEventArgs
- ProgressChangedEventArgs
- BackgroundWorker
- Implementación del patrón asincrónico basado en eventos
- Modelo asincrónico basado en eventos (EAP)
- Decidir cuándo implementar el patrón asincrónico basado en eventos
- Procedimientos recomendados para implementar el patrón asincrónico basado en eventos
- Cómo: Usar componentes que admiten el patrón asincrónico basado en eventos
- Cómo: Implementar un componente que admita el patrón asincrónico basado en eventos