tipos - ¿en c# que es una librería o biblioteca?




Entendiendo eventos y manejadores de eventos en C# (6)

Aquí hay un ejemplo de código que puede ayudar:

using System;
using System.Collections.Generic;
using System.Text;

namespace Event_Example
{
  // First we have to define a delegate that acts as a signature for the
  // function that is ultimately called when the event is triggered.
  // You will notice that the second parameter is of MyEventArgs type.
  // This object will contain information about the triggered event.

  public delegate void MyEventHandler(object source, MyEventArgs e);

  // This is a class which describes the event to the class that receives it.
  // An EventArgs class must always derive from System.EventArgs.

  public class MyEventArgs : EventArgs
  {
    private string EventInfo;

    public MyEventArgs(string Text) {
      EventInfo = Text;
    }

    public string GetInfo() {
      return EventInfo;
    }
  }

  // This next class is the one which contains an event and triggers it
  // once an action is performed. For example, lets trigger this event
  // once a variable is incremented over a particular value. Notice the
  // event uses the MyEventHandler delegate to create a signature
  // for the called function.

  public class MyClass
  {
    public event MyEventHandler OnMaximum;

    private int i;
    private int Maximum = 10;

    public int MyValue
    {
      get { return i; }
      set
      {
        if(value <= Maximum) {
          i = value;
        }
        else 
        {
          // To make sure we only trigger the event if a handler is present
          // we check the event to make sure it's not null.
          if(OnMaximum != null) {
            OnMaximum(this, new MyEventArgs("You've entered " +
              value.ToString() +
              ", but the maximum is " +
              Maximum.ToString()));
          }
        }
      }
    }
  }

  class Program
  {
    // This is the actual method that will be assigned to the event handler
    // within the above class. This is where we perform an action once the
    // event has been triggered.

    static void MaximumReached(object source, MyEventArgs e) {
      Console.WriteLine(e.GetInfo());
    }

    static void Main(string[] args) {
      // Now lets test the event contained in the above class.
      MyClass MyObject = new MyClass();
      MyObject.OnMaximum += new MyEventHandler(MaximumReached);
      for(int x = 0; x <= 15; x++) {
        MyObject.MyValue = x;
      }
      Console.ReadLine();
    }
  }
}

Entiendo el propósito de los eventos, especialmente en el contexto de la creación de interfaces de usuario. Creo que este es el prototipo para crear un evento:

public void EventName(object sender, EventArgs e);

¿Qué hacen los manejadores de eventos, por qué son necesarios y cómo puedo crear uno?


C # conoce dos términos, delegate y event . Vamos a empezar con el primero.

Delegar

Un delegate es una referencia a un método. Al igual que puede crear una referencia a una instancia:

MyClass instance = myFactory.GetInstance();

Puede usar un delegado para crear una referencia a un método:

Action myMethod = myFactory.GetInstance;

Ahora que tiene esta referencia a un método, puede llamar al método a través de la referencia:

MyClass instance = myMethod();

Pero ¿por qué lo harías? También puedes simplemente llamar a myFactory.GetInstance() directamente. En este caso puedes. Sin embargo, hay muchos casos en los que pensar en dónde no desea que el resto de la aplicación tenga conocimiento de myFactory o llamar a myFactory.GetInstance() directamente.

Una obvia es si desea poder reemplazar myFactory.GetInstance() en myOfflineFakeFactory.GetInstance() desde un lugar central (también conocido como patrón de método de fábrica ).

Patrón de método de fábrica

Entonces, si tiene una clase TheOtherClass y necesita usar myFactory.GetInstance() , así es como se verá el código sin los delegados (deberá informar a TheOtherClass sobre el tipo de su myFactory ):

TheOtherClass toc;
//...
toc.SetFactory(myFactory);


class TheOtherClass
{
   public void SetFactory(MyFactory factory)
   {
      // set here
   }

}

Si usas delegados, no tienes que exponer el tipo de mi fábrica:

TheOtherClass toc;
//...
Action factoryMethod = myFactory.GetInstance;
toc.SetFactoryMethod(factoryMethod);


class TheOtherClass
{
   public void SetFactoryMethod(Action factoryMethod)
   {
      // set here
   }

}

Por lo tanto, puede otorgar un delegado a otra clase para que lo use, sin exponer su tipo a ellos. Lo único que está exponiendo es la firma de su método (cuántos parámetros tiene y tales).

"Firma de mi método", ¿dónde escuché eso antes? O sí, interfaces !!! Las interfaces describen la firma de una clase entera. ¡Piense en los delegados que describen la firma de un solo método!

Otra gran diferencia entre una interfaz y un delegado es que cuando escribe su clase, no tiene que decirle a C # "este método implementa ese tipo de delegado". Con las interfaces, debe decir "esta clase implementa ese tipo de interfaz".

Además, una referencia de delegado puede (con algunas restricciones, ver más abajo) hacer referencia a múltiples métodos (llamados MulticastDelegate ). Esto significa que cuando llame al delegado, se ejecutarán múltiples métodos explícitamente adjuntos. Una referencia de objeto siempre puede hacer referencia solo a un objeto.

Las restricciones para un MulticastDelegate son que la firma (método / delegado) no debe tener ningún valor de retorno ( void ) y las palabras clave out y ref no se usan en la firma. Obviamente, no puede llamar a dos métodos que devuelven un número y esperar que devuelvan el mismo número. Una vez que la firma cumple, el delegado es automáticamente un MulticastDelegate .

Evento

Los eventos son solo propiedades (como los campos obtener, establecer, propiedades a instancia) que exponen la suscripción al delegado desde otros objetos. Estas propiedades, sin embargo, no admiten get; set ;. En su lugar son compatibles con agregar; eliminar;

Para que puedas tener:

    Action myField;

    public event Action MyProperty
    {
        add { myField += value; }
        remove { myField -= value; }
    }

Uso en la interfaz de usuario (WinForms)

Entonces, ahora sabemos que un delegado es una referencia a un método y que podemos tener un evento para que el mundo sepa que pueden darnos sus métodos para ser referenciados por nuestro delegado, y somos un botón de UI, entonces: Puede preguntar a cualquier persona que esté interesada en si me hicieron clic para registrar su método con nosotros (a través del evento que expusimos). Podemos usar todos los métodos que se nos dieron y hacer referencia a ellos por nuestro delegado. Y luego, esperaremos y esperaremos ... hasta que un usuario aparezca y haga clic en ese botón, entonces tendremos suficientes razones para invocar al delegado. Y como el delegado hace referencia a todos los métodos que se nos han dado, todos esos métodos serán invocados. No sabemos qué hacen esos métodos, ni sabemos qué clase implementa esos métodos. Lo único que nos importa es que alguien haya estado interesado en que nos hicieran clic y nos dio una referencia a un método que cumplía con nuestra firma deseada.

Java

Los lenguajes como Java no tienen delegados. Ellos usan interfaces en su lugar. La forma en que lo hacen es pedirle a cualquier persona interesada en que "se nos haga clic" para que implemente cierta interfaz (con un cierto método al que podemos llamar), luego nos proporcione la instancia completa que implementa la interfaz. Mantenemos una lista de todos los objetos que implementan esta interfaz, y podemos llamar a su 'cierto método al que podemos llamar' cada vez que hacemos clic.


Estoy de acuerdo con KE50, excepto que veo la palabra clave 'evento' como un alias para 'ActionCollection' ya que el evento contiene una colección de acciones a realizar (es decir, el delegado).

using System;

namespace test{

class MyTestApp{
    //The Event Handler declaration
    public delegate void EventAction();

    //The Event Action Collection 
    //Equivalent to 
    //  public List<EventAction> EventActions=new List<EventAction>();
    //        
    public event EventAction EventActions;

    //An Action
    public void Hello(){
        Console.WriteLine("Hello World of events!");
    }
    //Another Action
    public void Goodbye(){
        Console.WriteLine("Goodbye Cruel World of events!");
    }

    public static void Main(){
        MyTestApp TestApp = new MyTestApp();

        //Add actions to the collection
        TestApp.EventActions += TestApp.Hello;
        TestApp.EventActions += TestApp.Goodbye;

        //Invoke all event actions
        if (TestApp.EventActions!= null){
            //this peculiar syntax hides the invoke 
            TestApp.EventActions();
            //using the 'ActionCollection' idea:
            // foreach(EventAction action in TestApp.EventActions)
            //     action.Invoke();
        }
    }

}   

}

Mi comprensión de los acontecimientos es;

Delegar:

Una variable para mantener la referencia al método / métodos a ser ejecutados. Esto hace posible pasar métodos como una variable.

Pasos para crear y convocar el evento:

  1. El evento es una instancia de un delegado.

  2. Como un evento es una instancia de un delegado, primero tenemos que definir al delegado.

  3. Asigne el método / métodos que se ejecutarán cuando se active el evento ( Llamando al delegado )

  4. Dispara el evento ( Llama al delegado )

Ejemplo:

using System;

namespace test{
    class MyTestApp{
        //The Event Handler declaration
        public delegate void EventHandler();

        //The Event declaration
        public event EventHandler MyHandler;

        //The method to call
        public void Hello(){
            Console.WriteLine("Hello World of events!");
        }

        public static void Main(){
            MyTestApp TestApp = new MyTestApp();

            //Assign the method to be called when the event is fired
            TestApp.MyHandler = new EventHandler(TestApp.Hello);

            //Firing the event
            if (TestApp.MyHandler != null){
                TestApp.MyHandler();
            }
        }

    }   

}

Solo para agregar a las grandes respuestas existentes aquí, basándose en el código en el aceptado, que usa un delegate void MyEventHandler(string foo) ...

Debido a que el compilador conoce el tipo de delegado del evento SomethingHappened , esto:

myObj.SomethingHappened += HandleSomethingHappened;

Es totalmente equivalente a:

myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened);

Y los manejadores también se pueden desregistrar con -= así:

// -= removes the handler from the event's list of "listeners":
myObj.SomethingHappened -= HandleSomethingHappened;

Para completar, el aumento del evento se puede hacer así, solo en la clase propietaria del evento:

//Firing the event is done by simply providing the arguments to the event:
var handler = SomethingHappened; // thread-local copy of the event
if (handler != null) // the event is null if there are no listeners!
{
    handler("Hi there!");
}

Se necesita la copia local del subproceso del controlador para asegurarse de que la invocación es segura para el subproceso; de lo contrario, un subproceso podría ir y anular el registro del último controlador para el evento inmediatamente después de verificar si era null , y tendríamos una "diversión" NullReferenceException allí.

C # 6 introdujo una buena mano corta para este patrón. Utiliza el operador de propagación nula.

SomethingHappened?.Invoke("Hi there!");

editor: donde suceden los eventos. El publicador debe especificar qué delegado está utilizando la clase y generar los argumentos necesarios, pasar esos argumentos y al delegado.

Suscriptor: donde suceda la respuesta. El suscriptor debe especificar métodos para responder a los eventos. Estos métodos deben tomar el mismo tipo de argumentos que el delegado. El suscriptor luego agrega este método al delegado del editor.

Por lo tanto, cuando el evento ocurra en el editor, el delegado recibirá algunos argumentos del evento (datos, etc.), pero el editor no tiene idea de lo que ocurrirá con todos estos datos. Los suscriptores pueden crear métodos en su propia clase para responder a los eventos en la clase del editor, para que los suscriptores puedan responder a los eventos del editor.





event-handling