c# ¿en - Diferencia entre eventos y delegados y sus respectivas aplicaciones





librería biblioteca? (9)


para entender las diferencias puedes mirar estos 2 ejemplos

Ejemplo con Delegados (Acción en este caso que es un tipo de delegado que no devuelve valor)

public class Animal
{
    public Action Run {get; set;}

    public void RaiseEvent()
    {
        if (Run != null)
        {
            Run();
        }
    }
}

para usar el delegado deberías hacer algo como esto

Animale animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();

este código funciona bien, pero podrías tener algunos puntos débiles.

Por ejemplo, si escribo esto

animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;

con la última línea de código anulé los comportamientos previos solo con un + faltante (he usado + lugar de += )

Otro punto débil es que cada clase que use su clase Animal puede generar RaiseEvent llamándolo animal.RaiseEvent() .

Para evitar estos puntos débiles puedes usar events en c #.

Tu clase de Animal cambiará de esta manera

public class ArgsSpecial :EventArgs
   {
        public ArgsSpecial (string val)
        {
            Operation=val;
        }

        public string Operation {get; set;}
   } 



 public class Animal
    {
       public event EventHandler<ArgsSpecial> Run = delegate{} //empty delegate. In this way you are sure that value is always != null because no one outside of the class can change it

       public void RaiseEvent()
       {  
          Run(this, new ArgsSpecial("Run faster"));
       }
    }

llamar eventos

 Animale animal= new Animal();
 animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
 animal.RaiseEvent();

Diferencias

  1. No está utilizando una propiedad pública sino un campo público (con eventos el compilador protege sus campos del acceso no deseado)
  2. Los eventos no se pueden asignar directamente. En este caso, no puede hacer el error anterior que he mostrado al anular el comportamiento.
  3. Nadie fuera de tu clase puede plantear el evento.
  4. Los eventos se pueden incluir en una declaración de interfaz, mientras que un campo no puede

notas

EventHandler se declara como el siguiente delegado:

public delegate void EventHandler (object sender, EventArgs e)

toma un remitente (del tipo de objeto) y argumentos de evento. El remitente es nulo si proviene de métodos estáticos.

También puede utilizar EventHAndler en este ejemplo que use EventHandler<ArgsSpecial>

consulte here documentación sobre EventHandler

No veo ventajas de usar eventos sobre delegados, aparte de ser azúcar sintáctica. Tal vez estoy malinterpretando, pero parece que ese evento es solo un marcador de posición para el delegado.

¿Me explicarías las diferencias y cuándo usarlas? ¿Cuáles son las ventajas y desventajas? Nuestro código está muy arraigado con los eventos, y quiero llegar al fondo del mismo.

¿Cuándo usarías delegados sobre eventos y viceversa? Por favor, indique su experiencia en el mundo real con ambos, por ejemplo, en el código de producción.




Los eventos son azúcar sintáctico. Son deliciosos. Cuando veo un evento, sé qué hacer. Cuando veo un delegado, no estoy tan seguro.

La combinación de eventos con interfaces (más azúcar) lo convierte en un tentempié delicioso. Los delegados y las clases abstractas virtuales puras son mucho menos apetecibles.




Los eventos se marcan como tales en los metadatos. Esto permite que elementos como los diseñadores de Windows Forms o ASP.NET distingan los eventos de las meras propiedades del tipo de delegado y proporcionen el soporte adecuado para ellos (mostrándolos específicamente en la pestaña Eventos de la ventana Propiedades).

Otra diferencia de una propiedad de tipo delegado es que los usuarios solo pueden agregar y eliminar manejadores de eventos, mientras que con una propiedad de tipo delegado pueden establecer el valor:

someObj.SomeCallback = MyCallback;  // okay, replaces any existing callback
someObj.SomeEvent = MyHandler;  // not okay, must use += instead

Esto ayuda a aislar a los suscriptores del evento: puedo agregar mi controlador a un evento, y puedes agregar tu controlador al mismo evento, y no sobreescribirás accidentalmente mi controlador.




El event palabra clave es un modificador de alcance para delegados de multidifusión. Las diferencias prácticas entre esto y simplemente declarar un delegado de multidifusión son las siguientes:

  • Puede usar event en una interfaz.
  • El acceso de invocación al delegado de multidifusión está limitado a la clase declarante. El comportamiento es como si el delegado fuera privado para la invocación. A los efectos de la asignación, el acceso es tal como lo especifica un modificador de acceso explícito (por ejemplo, public event ).

Como cuestión de interés, puede aplicar + y - a delegados de multidifusión, y esta es la base de la sintaxis += y -= para la asignación de combinación de delegados a eventos. Estos tres fragmentos son equivalentes:

B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = B + C;

Muestra dos, que ilustra tanto la asignación directa como la asignación de combinación.

B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = B;
A += C;

Muestra tres: sintaxis más familiar. Probablemente esté familiarizado con la asignación de null para eliminar todos los controladores.

B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = null;
A += B;
A += C;

Al igual que las propiedades, los eventos tienen una sintaxis completa que nadie usa. Esta:

class myExample 
{
  internal EventHandler eh;

  public event EventHandler OnSubmit 
  { 
    add 
    {
      eh = Delegate.Combine(eh, value) as EventHandler;
    }
    remove
    {
      eh = Delegate.Remove(eh, value) as EventHandler;
    }
  }

  ...
}

... hace exactamente lo mismo que esto:

class myExample 
{
  public event EventHandler OnSubmit;
}

Los métodos de agregar y quitar son más conspicuos en la sintaxis bastante rígida que usa VB.NET (sin sobrecargas del operador).




Desde el punto de vista técnico, otras respuestas han abordado las diferencias.

Desde una perspectiva semántica, los eventos son acciones planteadas por un objeto cuando se cumplen ciertas condiciones. Por ejemplo, mi clase Stock tiene una propiedad llamada Límite, y genera un evento cuando los precios de las acciones alcanzan el Límite. Esta notificación se realiza a través de un evento. Si alguien realmente se preocupa por este evento y se suscribe está más allá de la preocupación de la clase propietaria.

Un delegado es un término más genérico para describir una construcción similar a un puntero en términos de C / C ++. Todos los delegados en .Net son delegados de multidifusión. Desde una perspectiva semántica, generalmente se usan como una especie de entrada. En particular, son una forma perfecta de implementar el Patrón de estrategia . Por ejemplo, si quiero ordenar una Lista de objetos, puedo proporcionar una estrategia de comparación al método para decirle a la implementación cómo comparar dos objetos.

He usado los dos métodos en el código de producción. Toneladas de mis objetos de datos notifican cuando se cumplen ciertas propiedades. El ejemplo más básico, cuando una propiedad cambia, se genera un evento PropertyChanged (vea la interfaz INotifyPropertyChanged). He usado delegados en el código para proporcionar diferentes estrategias para convertir ciertos objetos en cadenas. Este ejemplo particular fue una lista glorificada de ToString () de implementaciones para un tipo de objeto particular para mostrarlo a los usuarios.




La diferencia entre los eventos y los delegados es mucho más pequeña de lo que solía pensar. Acabo de publicar un video súper corto de YouTube sobre el tema: https://www.youtube.com/watch?v=el-kKK-7SBU

¡Espero que esto ayude!




Editar # 1 ¿ Cuándo usarías delegados sobre eventos y vs.versa? Por favor, indique su experiencia en el mundo real con ambos, por ejemplo, en el código de producción.

Cuando diseño mis propias API, defino delegados que se pasan como parámetros a los métodos, o a los constructores de las clases:

  • De modo que un método puede implementar un patrón simple de 'método de plantilla' (como, por ejemplo, los delegados de Predicate y Action se pasan a las clases de colección genéricas de .Net)
  • O para que la clase pueda hacer una "devolución de llamada" (por lo general, una devolución de llamada a un método de la clase que lo creó).

Estos delegados generalmente no son opcionales en tiempo de ejecución (es decir, no deben ser null ).

Tiendo a no usar eventos; pero cuando utilizo eventos, los utilizo para señalar opcionalmente eventos a cero, uno o más clientes que podrían estar interesados, es decir, cuando tiene sentido que una clase (por ejemplo, la clase System.Windows.Form ) debería existir y ejecutarse ya sea o no, ningún cliente ha agregado un controlador de eventos a su evento (por ejemplo, existe el evento 'mouse down' del formulario, pero es opcional si un cliente externo está interesado en instalar un controlador de eventos en ese evento).




Aunque los eventos se implementan típicamente con delegados de multidifusión, no es obligatorio que se utilicen de esa manera. Si una clase expone un evento, eso significa que la clase expone dos métodos. Sus significados son, en esencia:

  1. Aquí hay un delegado. Por favor, invoca cuando sucede algo interesante.
  2. Aquí hay un delegado. Debería destruir toda referencia al mismo tan pronto como sea conveniente (y no volver a llamarlo).

La forma más común para que una clase maneje un evento que expone es definir un delegado de multidifusión y agregar / eliminar cualquier delegado que se transfiera a los métodos anteriores, pero no es obligatorio que funcionen de esa manera. Desafortunadamente, la arquitectura del evento falla en hacer algunas cosas que hubieran hecho los enfoques alternativos mucho más limpios (ej. Hacer que el método de suscripción devuelva un MethodInvoker, que el suscriptor guardara, cancelar la suscripción a un evento, simplemente invocar el método devuelto) para que los delegados multicast son de lejos el enfoque más común.




Ok, esto no es realmente una respuesta a la pregunta, pero si está buscando cómo hacer que su propio delegado quizás algo mucho más simple podría ser una mejor respuesta para usted.

Apenas implemento a mis delegados porque rara vez necesito. Puedo tener SOLO UN delegado para un objeto delegado. Por lo tanto, si desea que su delegado de una forma de comunicación / transmisión de datos sea mucho mejor que con las notificaciones.

NSNotification puede pasar objetos a más de un destinatario y es muy fácil de usar. Funciona así:

El archivo MyClass.m debería verse así

#import "MyClass.h"
@implementation MyClass 

- (void) myMethodToDoStuff {
//this will post a notification with myClassData (NSArray in this case)  in its userInfo dict and self as an object
[[NSNotificationCenter defaultCenter] postNotificationName:@"myClassUpdatedData"
                                                    object:self
                                                  userInfo:[NSDictionary dictionaryWithObject:selectedLocation[@"myClassData"] forKey:@"myClassData"]];
}
@end

Para usar su notificación en otras clases: agregue clase como observador:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];

Implementar el selector:

- (void) otherClassUpdatedItsData:(NSNotification *)note {
    NSLog(@"*** Other class updated its data ***");
    MyClass *otherClass = [note object];  //the object itself, you can call back any selector if you want
    NSArray *otherClassData = [note userInfo][@"myClassData"]; //get myClass data object and do whatever you want with it
}

No olvides eliminar a tu clase como observador si

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}




c# design events delegates