C# delegate v.s. EventHandler

情到浓时终转凉″ 提交于 2019-12-03 03:12:01

问题


I want to send an alert message to any subscribers when a trap occurred.

The code I created works fine using a delegate method myDelegate del.

My questions are:

  1. I want to know whether it's better to use EventHandler instead of a delegate? I'm not sure what the differences are between a delegate and an EventHandler in my case.

  2. notify(trapinfo t), that's what I've done here to get trap information. But it seems not to be a good idea. I read some online tutorial lesson introducing passing delegate object; I'm wondering if it's appropriate in my case? And how should I do it? Any suggestions?

Thanks a lot :)

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

Update 2013-08-12

How about the observer/observable design pattern, that looks great in my case (EventHandler).

In my case, a machine subscribes to a trap messenger. (Add a machine to an invocation list) Once a trap occurred, I send a message to all machines which are subscribed. (Call HandleEvent to handle it)

Advantages:

  • don't care about GetInvocationList() anymore, just use (+=) and (-=) to decide whom to send the trap.

  • It's easier to understand the logic of my program.

I know there are several ways to do it, but I wish I could analyze its pros and cons.

And thanks for your comments and suggestions, that would be very helpful!

I read the MSDN EventArgs article which Matthew Watson suggested.

Here's my Event Version:

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

回答1:


The difference between event and delegate is that:

event declaration adds a layer of protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list, and only allows adding or removing targets from the invocation list

See What are the differences between delegates and events?

2) As I see it, your subscriber should not change delegates freely. One subscriber can assign = to it instead of adding +=. This will assign a new delegate, therefore, the previous delegate with its invocation list will be lost and previous subscribers will not be called anymore. So you should use Event for sure. Or you can change your code to make your delegate private and write additional functions for manipulating it to define your own event behavior.

 //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);



回答2:


It is much better to use an event for your example.

  • An event is understood by the Visual Studio Form and WPF designers, so you can use the IDE to subscribe to events.

  • When raising events, there is no need for you to write your own foreach handling to iterate through them.

  • events are the way that most programmers will expect this functionality to be accessed.

  • If you use a delegate, the consuming code can mess around with it in ways that you will want to prevent (such as resetting its invocation list). events do not allow that to happen.

As for your second question: Using an event you would create a class derived from EventArgs to hold the data, and pass that to the event when you raise it. The consumer will then have access to it.

See here for details: http://msdn.microsoft.com/en-us/library/system.eventargs.aspx



来源:https://stackoverflow.com/questions/18170282/c-sharp-delegate-v-s-eventhandler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!