web-dev-qa-db-fra.com

Délégué C # c. Gestionnaire d'événements

Je souhaite envoyer un message d'alerte à tous les abonnés lorsqu'un piège s'est produit.

Le code que j'ai créé fonctionne très bien en utilisant une méthode déléguée myDelegate del.

Mes questions sont:

  1. Je veux savoir s'il vaut mieux utiliser EventHandler au lieu d'un délégué? Je ne sais pas quelles sont les différences entre un délégué et un EventHandler dans mon cas.

  2. notify(trapinfo t), c'est ce que j'ai fait ici pour obtenir des informations sur les pièges. Mais cela ne semble pas être une bonne idée. J'ai lu une leçon de tutoriel en ligne présentant un objet délégué qui passe; Je me demande si c'est approprié dans mon cas? Et comment dois-je le faire? Aucune suggestion?

Merci beaucoup :)

Mon code:

public class trapinfo
    {
        public string info;
        public string ip;
        public string cause;
    }

    public class trap
    {
        public delegate void myDelegate(trapinfo t);
        public myDelegate del;

        trapinfo info = new trapinfo();

        public void run()
        {
            //While(true) 
            // If a trap occurred, notify the subscriber
            for (; ; )
            {
                Thread.Sleep(500);
                foreach (myDelegate d in del.GetInvocationList())
                {
                    info.cause = "Shut Down";
                    info.ip = "192.168.0.1";
                    info.info = "Test";
                    d.Invoke(info);
                }
            }
        }
    }
    public class machine
    {
        private int _occuredtime=0;

        public trapinfo info = new trapinfo();
        public void notify(trapinfo t)
        {
            ++_occuredtime;
            info.cause = t.cause;
            info.info = t.info;
            info.ip = t.ip;
            getInfo();
        }
        public void subscribe(trap t)
        {
            t.del += new trap.myDelegate(notify);
        }
        public void getInfo()
        {
            Console.WriteLine("<Alert>: cauese/{0}, info/ {1}, ip/{2}, time/{3}",
                info.cause, info.info, info.ip,_occuredtime);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            trap t = new trap();
            machine machineA = new machine();
            machineA.subscribe(t);
            t.run();
        }
    }

Mise à jour 2013-08-12

Que diriez-vous du modèle de conception observateur/observable , qui a fière allure dans mon cas (EventHandler).

Dans mon cas, une machine souscrit à un messager piège. (Ajouter une machine à une liste d'invocation) Une fois qu'un piège s'est produit, j'envoie un message à toutes les machines abonnées. (Appelez HandleEvent pour le gérer)

Avantages:

  • ne vous souciez plus de GetInvocationList(), utilisez simplement (+=) et (-=) pour décider qui envoyer le piège.

  • Il est plus facile de comprendre la logique de mon programme.

Je sais qu'il y a plusieurs façons de le faire, mais j'aimerais pouvoir analyser ses avantages et ses inconvénients.

Et merci pour vos commentaires et suggestions, ce serait très utile!

J'ai lu l'article MSDN EventArgs que Matthew Watson a suggéré.

Voici ma version d'événement:

public class TrapInfoEventArgs : EventArgs
{
    public int info { get; set; }
    public string  ip { get; set; }
    public string cause { get; set; }
}
public class trap
{
    public event EventHandler<TrapInfoEventArgs> TrapOccurred;

    protected virtual void OnTrapOccurred(TrapInfoEventArgs e)
    {
        EventHandler<TrapInfoEventArgs> handler = TrapOccurred;
        if (handler != null)
        {
            handler(this, e);
        }
    }


    public void run()
    {
        //While(true) 
        // If a trap occurred, notify the subscriber
        for (; ; )
        {
            Thread.Sleep(500);
            TrapInfoEventArgs args = new TrapInfoEventArgs();
            args.cause = "Shut Down";
            OnTrapOccurred(args);
        }
    }
}
public class machine
{
    public void c_TrapOccurred(object sender, TrapInfoEventArgs e)
    {
        Console.WriteLine("<Alert>: cauese/{0}, info/ {1}, ip/{2}, time/{3}",
            e.cause, e.info, e.ip, DateTime.Now.ToString());
    }
}
class Program
{
    static void Main(string[] args)
    {
        trap t = new trap();
        machine machineA = new machine();
        t.TrapOccurred += machineA.c_TrapOccurred; //notify machine A
        t.run();
    }
}
19
Hsu Wei Cheng

La différence entre l'événement et le délégué est que:

la déclaration d'événement ajoute une couche de protection sur l'instance déléguée. Cette protection empêche les clients du délégué de réinitialiser le délégué et sa liste d'invocation et autorise uniquement l'ajout ou la suppression de cibles de la liste d'invocation

Voir Quelles sont les différences entre les délégués et les événements?

2) Selon moi, votre abonné ne devrait pas changer librement de délégué. Un abonné peut attribuer = au lieu d'ajouter +=. Cela affectera un nouveau délégué, par conséquent, le délégué précédent avec sa liste d'invocation sera perdu et les abonnés précédents ne seront plus appelés. Vous devez donc certainement utiliser Event. Ou vous pouvez modifier votre code pour rendre votre délégué privé et écrire des fonctions supplémentaires pour le manipuler afin de définir votre propre comportement d'événement.

 //preventing direct assignment
 private myDelegate del ;

    public void AddCallback(myDelegate m){
        del += m;
    }

    public void RemoveCallback(myDelegate m){
        del -= m;
    }

    //or
    public static trap operator +(trap x,myDelegate m){
        x.AddCallback(m);
        return x;
    }
    public static trap operator -(trap x, myDelegate m)
    {
        x.RemoveCallback(m);
        return x;
    }

//usage  

//t.AddCallback(new trap.myDelegate(notify));
  t+=new trap.myDelegate(notify);
17
qwr

Il est préférable d'utiliser un event pour votre exemple.

  • Un event est compris par les concepteurs Visual Studio Form et WPF, vous pouvez donc utiliser le IDE pour vous abonner aux événements.

  • Lorsque vous augmentez events, vous n'avez pas besoin d'écrire votre propre gestion foreach pour les parcourir.

  • events est la façon dont la plupart des programmeurs s'attendent à ce que cette fonctionnalité soit accessible.

  • Si vous utilisez un délégué, le code consommateur peut jouer avec lui de façons que vous voudrez empêcher (comme la réinitialisation de sa liste d'invocation). events ne permet pas que cela se produise.

Quant à votre deuxième question: à l'aide d'un event, vous créeriez une classe dérivée de EventArgs pour contenir les données et la transmettriez à l'événement lorsque vous les augmenteriez. Le consommateur y aura alors accès.

Voir ici pour plus de détails: http://msdn.Microsoft.com/en-us/library/system.eventargs.aspx

8
Matthew Watson