[C#] Capire eventi e gestori di eventi in C #


Answers

C # conosce due termini, delegate ed event . Iniziamo con il primo.

Delegare

Un delegate è un riferimento a un metodo. Proprio come puoi creare un riferimento a un'istanza:

MyClass instance = myFactory.GetInstance();

È possibile utilizzare un delegato per creare un riferimento a un metodo:

Action myMethod = myFactory.GetInstance;

Ora che hai questo riferimento a un metodo, puoi chiamare il metodo tramite il riferimento:

MyClass instance = myMethod();

Ma perché dovresti? Puoi anche chiamare direttamente myFactory.GetInstance() . In questo caso puoi Tuttavia, ci sono molti casi in cui pensare a dove non si desidera che il resto dell'applicazione abbia conoscenza di myFactory o chiamare direttamente myFactory.GetInstance() .

Un ovvio è se si vuole essere in grado di sostituire myFactory.GetInstance() in myOfflineFakeFactory.GetInstance() da una posizione centrale (cioè pattern del metodo factory ).

Modello metodo di fabbrica

Quindi, se hai una classe TheOtherClass e ha bisogno di usare myFactory.GetInstance() , questo è il modo in cui il codice apparirà senza delegati (dovrai far sapere a TheOtherClass del tipo di myFactory ):

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


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

}

Se si utilizzano i delegati, non è necessario esporre il tipo della mia fabbrica:

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


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

}

Pertanto, puoi dare un delegato a qualche altra classe da usare, senza esporre il tuo tipo a loro. L'unica cosa che stai esponendo è la firma del tuo metodo (quanti parametri hai e così via).

"Firma del mio metodo", dove l'ho sentito prima? O sì, interfacce !!! le interfacce descrivono la firma di un'intera classe. Pensa ai delegati come a descrivere la firma di un solo metodo!

Un'altra grande differenza tra un'interfaccia e un delegato, è che quando scrivi la tua classe, non devi dire a C # "questo metodo implementa quel tipo di delegato". Con le interfacce devi dire "questa classe implementa quel tipo di interfaccia".

Inoltre, un riferimento delegato può (con alcune restrizioni, vedi sotto) riferimenti a più metodi (chiamati MulticastDelegate ). Ciò significa che quando si chiama il delegato, verranno eseguiti più metodi esplicitamente collegati. Un riferimento a un oggetto può sempre fare riferimento solo a un oggetto.

Le restrizioni per un MulticastDelegate sono che la firma (metodo / delegato) non deve avere alcun valore di ritorno ( void ) e le parole chiave out e ref non vengono utilizzate nella firma. Ovviamente, non è possibile chiamare due metodi che restituiscono un numero e aspettarsi che restituiscano lo stesso numero. Una volta che la firma è conforme, il delegato è automaticamente un MulticastDelegate .

Evento

Gli eventi sono solo proprietà (come get, set, proprietà sui campi di istanza) che espongono la sottoscrizione al delegato da altri oggetti. Queste proprietà, tuttavia, non supportano get; set ;. Invece supportano add: remove;

Quindi puoi avere:

    Action myField;

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

Utilizzo in UI (WinForms)

Quindi, ora sappiamo che un delegato è un riferimento a un metodo e che possiamo avere un evento per far sapere al mondo che possono darci i loro metodi per essere referenziati dal nostro delegato, e siamo un pulsante dell'interfaccia utente, quindi: posso chiedere a chiunque sia interessato a se sono stato cliccato, di registrare il loro metodo con noi (tramite l'evento che abbiamo esposto). Possiamo usare tutti quei metodi che ci sono stati dati e fare riferimento a loro dal nostro delegato. E poi, aspetteremo e aspetteremo .... finché un utente non arriva e fa clic su quel pulsante, allora avremo abbastanza motivi per invocare il delegato. E poiché il delegato fa riferimento a tutti quei metodi che ci sono stati dati, tutti i metodi saranno invocati. Non sappiamo cosa facciano quei metodi, né sappiamo quale classe implementa tali metodi. Tutto quello che ci interessa è che qualcuno fosse interessato a farci fare clic e ci ha dato un riferimento a un metodo che rispettava la nostra firma desiderata.

Giava

Lingue come Java non hanno delegati. Usano invece le interfacce. Il modo in cui lo fanno è chiedere a chiunque sia interessato a "essere cliccato", implementare una determinata interfaccia (con un certo metodo che possiamo chiamare), quindi fornirci l'intera istanza che implementa l'interfaccia. Possiamo tenere un elenco di tutti gli oggetti che implementano questa interfaccia e possiamo chiamare il loro "metodo certo che possiamo chiamare" ogni volta che clicchiamo.

Question

Comprendo lo scopo degli eventi, specialmente nel contesto della creazione di interfacce utente. Penso che questo sia il prototipo per la creazione di un evento:

public void EventName(object sender, EventArgs e);

Cosa fanno i gestori di eventi, perché sono necessari e come posso crearne uno?




//This delegate can be used to point to methods
//which return void and take a string.
public delegate void MyDelegate(string foo);

//This event can cause any method which conforms
//to MyEventHandler to be called.
public event MyDelegate MyEvent;

//Here is some code I want to be executed
//when SomethingHappened fires.
void MyEventHandler(string foo)
{
    //Do some stuff
}

//I am creating a delegate (pointer) to HandleSomethingHappened
//and adding it to SomethingHappened's list of "Event Handlers".
myObj.MyEvent += new MyDelegate (MyEventHandler);



Questa è in realtà la dichiarazione per un gestore di eventi: un metodo che verrà chiamato quando viene attivato un evento. Per creare un evento, dovresti scrivere qualcosa del genere:

public class Foo
{
    public event EventHandler MyEvent;
}

E poi puoi iscriverti all'evento in questo modo:

Foo foo = new Foo();
foo.MyEvent += new EventHandler(this.OnMyEvent);

Con OnMyEvent () definito in questo modo:

private void OnMyEvent(object sender, EventArgs e)
{
    MessageBox.Show("MyEvent fired!");
}

Ogni volta che Foo spegne MyEvent , viene chiamato il gestore OnMyEvent .

Non è sempre necessario utilizzare un'istanza di EventArgs come secondo parametro. Se si desidera includere informazioni aggiuntive, è possibile utilizzare una classe derivata da EventArgs ( EventArgs è la base per convenzione). Ad esempio, se si guardano alcuni degli eventi definiti su Control in WinForms o FrameworkElement in WPF, è possibile visualizzare esempi di eventi che passano informazioni aggiuntive ai gestori di eventi.




La mia comprensione degli eventi è;

Delegare:

Una variabile per mantenere il riferimento al metodo / metodi da eseguire. Ciò rende possibile passare metodi come una variabile.

Passi per la creazione e la chiamata dell'evento:

  1. L'evento è un'istanza di un delegato

  2. Poiché un evento è un'istanza di un delegato, dobbiamo prima definire il delegato.

  3. Assegna il metodo / i metodi da eseguire quando viene attivato l'evento ( Chiamando il delegato )

  4. Fai fuoco sull'evento ( Chiama il delegato )

Esempio:

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

    }   

}