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.
En .NET, el patrón de diseño de observador se implementa como un conjunto de interfaces. La System.IObservable<T> interfaz representa el proveedor de datos, que también es responsable de proporcionar una IDisposable implementación que permita a los observadores cancelar la suscripción de las notificaciones. La System.IObserver<T> interfaz representa el observador.
En este artículo se describen los procedimientos recomendados que se deben seguir al implementar el patrón de diseño de observador con estas interfaces.
Considerar alternativas antes de implementar
Las interfaces IObservable<T> y IObserver<T> son muy adecuadas para escenarios de notificaciones basadas en push, pero otros patrones de .NET pueden encajar mejor. Para una notificación sencilla dentro de una sola aplicación, use eventos. Para secuencias asincrónicas basadas en extracción en las que el consumidor controla el ritmo, use IAsyncEnumerable<T>. Para los patrones de productor-consumidor con contrapresión, use System.Threading.Channels. Para la composición, el filtrado y la transformación de eventos complejos, use el paquete System.Reactive (Rx.NET) en lugar de implementar directamente IObservable<T>. Para obtener más información, vea Patrón de diseño de observador.
Usar un tipo independiente para los datos de notificación
El objeto que contiene los datos que el proveedor envía a sus observadores corresponde al parámetro de tipo genérico de IObservable<T> y IObserver<T>. Aunque este objeto puede ser el mismo que la IObservable<T> implementación, defina como un tipo independiente. Un tipo de datos dedicado mantiene las responsabilidades del proveedor independientes de la carga de notificación y facilita la evolución de la API.
No confíe en el orden de notificación
El orden en que los observadores reciben notificaciones no está definido. El proveedor puede usar cualquier método para determinar el orden, por lo que no escriba observadores que dependan de recibir notificaciones antes o después de otro observador.
Hacer que la suscripción y eliminación de subprocesos sean seguras
Normalmente, un proveedor implementa el IObservable<T>.Subscribe método agregando un observador a una lista de suscriptores representada por un objeto de colección e implementa el IDisposable.Dispose método quitando el observador de esa lista. Un observador puede llamar a estos métodos en cualquier momento. El contrato entre proveedor y observador no especifica quién es responsable de cancelar la suscripción después del método de devolución de llamada IObserver<T>.OnCompleted, por lo que tanto el proveedor como el observador podrían intentar eliminar el mismo elemento de la lista.
Para evitar condiciones de carrera, haga que ambos métodos Subscribe y Dispose sean seguros para la ejecución en varios hilos. Normalmente, esto implica el uso de una colección simultánea o un bloqueo. Las implementaciones que no son seguras en entornos multihilo deben documentar explícitamente que no lo son.
Documentar cualquier garantía adicional de contrato
Especifique las garantías adicionales en una capa sobre el contrato de proveedor o observador. Cuando impone otros requisitos, llámalos claramente para que los usuarios no se confundan con el contrato de observador.
Tratar las excepciones como informativas
Debido al acoplamiento flexible entre un proveedor de datos y un observador, las excepciones del patrón de diseño del observador están pensadas para ser informativos. Esta característica afecta a cómo los proveedores y observadores controlan las excepciones.
Llamar a OnError solo cuando las actualizaciones no pueden continuar
El OnError método está pensado como un mensaje informativo para los observadores, al igual que el IObserver<T>.OnNext método . Sin embargo, el OnNext método proporciona a un observador datos actuales o actualizados, mientras que el OnError método indica que el proveedor no puede proporcionar datos válidos.
Siga estos procedimientos recomendados cuando controle excepciones y llame al OnError método :
- El proveedor debe controlar sus propias excepciones si tiene requisitos específicos.
- El proveedor no debe esperar ni exigir que los observadores gestionen las excepciones de ninguna forma concreta.
- El proveedor debe llamar al OnError método cuando controla una excepción que pone en peligro su capacidad de proporcionar actualizaciones. Pase información sobre estas excepciones al observador. En otros casos, no es necesario notificar a los observadores una excepción.
Después de que el proveedor llame al OnError método o IObserver<T>.OnCompleted , no debe haber más notificaciones y el proveedor puede cancelar la suscripción de sus observadores. Sin embargo, los observadores también pueden darse de baja ellos mismos en cualquier momento, incluso antes y después de recibir una notificación de OnError o IObserver<T>.OnCompleted. El patrón de diseño del observador no determina si el proveedor o el observador son responsables de anular la suscripción, por lo que ambos podrían intentar cancelar la suscripción. Normalmente, cuando los observadores cancelan la suscripción, se quitan de una colección de suscriptores. En una aplicación de un único hilo, la implementación de IDisposable.Dispose debe asegurarse de que una referencia a un objeto sea válida y de que el objeto pertenezca a la colección de suscriptores antes de intentar eliminarlo. En una aplicación multiproceso, use un bloqueo para proteger la colección de observadores.
Tratar las notificaciones OnError como informativas en los observadores
Cuando un observador recibe una notificación de error de un proveedor, el observador debe tratar la excepción como informativo y no debe ser necesaria para realizar ninguna acción concreta.
Siga estos procedimientos recomendados al responder a una OnError llamada de método desde un proveedor:
- No lance excepciones en implementaciones de interfaces como OnNext o OnError. Si el observador lanza excepciones, es de esperar que queden sin controlar.
- Para conservar la pila de llamadas, un observador que desee lanzar un objeto Exception que se pasó a su método OnError debe encapsular la excepción antes de lanzarla. Use un objeto de excepción estándar para este propósito.
No anular el registro en el método Subscribe
No intente anular el registro en el IObservable<T>.Subscribe método , ya que podría dar lugar a una referencia nula.
Adjuntar un observador a un solo proveedor
Aunque puede adjuntar un observador a varios proveedores, el patrón recomendado es adjuntar una IObserver<T> instancia a una IObservable<T> sola instancia.