简体   繁体   English

C#delegate vs EventHandler

[英]C# delegate v.s. EventHandler

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 . 我创建的代码使用委托方法myDelegate del工作正常。

My questions are: 我的问题是:

  1. I want to know whether it's better to use EventHandler instead of a delegate? 我想知道使用EventHandler而不是EventHandler是否更好? I'm not sure what the differences are between a delegate and an EventHandler in my case. 在我的情况下,我不确定委托和EventHandler之间的区别。

  2. notify(trapinfo t) , that's what I've done here to get trap information. notify(trapinfo t) ,这就是我在这里获取的陷阱信息。 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 更新2013-08-12

How about the observer/observable design pattern, that looks great in my case ( EventHandler ). 观察者/可观察的设计模式如何,在我的案例中看起来很棒( 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) (调用HandleEvent来处理它)

Advantages: 好处:

  • don't care about GetInvocationList() anymore, just use (+=) and (-=) to decide whom to send the trap. 不再关心GetInvocationList() ,只需使用(+=)(-=)来决定发送陷阱的对象。

  • 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. 我阅读了Matthew Watson建议的MSDN EventArgs文章。

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

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. 2)我认为,您的订阅者不应该自由更改代表。 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. 所以你应该确定使用Event。 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);

It is much better to use an event for your example. 为您的示例使用event要好得多。

  • An event is understood by the Visual Studio Form and WPF designers, so you can use the IDE to subscribe to events. Visual Studio窗体和WPF设计器可以理解event ,因此您可以使用IDE订阅事件。

  • When raising events , there is no need for you to write your own foreach handling to iterate through them. 在引发events ,您无需编写自己的foreach处理来迭代它们。

  • events are the way that most programmers will expect this functionality to be accessed. events是大多数程序员期望访问此功能的方式。

  • 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. events不允许这种情况发生。

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. 至于你的第二个问题:使用一个event你会创建一个派生自EventArgs的类来保存数据,并在你引发它时将它传递给事件。 The consumer will then have access to it. 然后消费者可以访问它。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM