C# 委托与 EventHandler

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18170282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:27:09  来源:igfitidea点击:

C# delegate v.s. EventHandler

c#delegatesevent-handlingobserver-pattern

提问by Hsu Wei Cheng

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 EventHandlerinstead of a delegate? I'm not sure what the differences are between a delegate and an EventHandlerin 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?

  1. 我想知道使用EventHandler代理是否更好?我不确定EventHandler在我的情况下委托和委托之间有什么区别。

  2. notify(trapinfo t),这就是我在这里所做的以获取陷阱信息。但这似乎不是一个好主意。我阅读了一些介绍传递委托对象的在线教程;我想知道它是否适合我的情况?我该怎么做?有什么建议?

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/observabledesign 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 HandleEventto handle it)

就我而言,一台机器订阅了一个陷阱信使。(将机器添加到调用列表)一旦发生陷阱,我会向所有订阅的机器发送消息。(打电话HandleEvent处理)

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.

  • 不用管GetInvocationList()了,就用(+=)(-=)决定把陷阱发给谁。

  • 更容易理解我的程序的逻辑。

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

采纳答案by qwr

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.

2)据我所知,您的订阅者不应随意更改代表。一个订阅者可以分配=给它而不是添加+=。这将分配一个新的委托,因此,先前的委托及其调用列表将丢失,并且不再调用先前的订阅者。所以你肯定应该使用 Event 。或者您可以更改您的代码以将您的委托设为私有并编写额外的函数来操作它以定义您自己的事件行为。

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

回答by Matthew Watson

It is much better to use an eventfor your example.

最好使用 anevent作为您的示例。

  • An eventis 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 foreachhandling to iterate through them.

  • eventsare 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). eventsdo not allow that to happen.

  • eventVisual Studio 窗体和 WPF 设计器理解An ,因此您可以使用 IDE 订阅事件。

  • 在提高 时events,您无需编写自己的foreach处理来遍历它们。

  • events是大多数程序员期望访问此功能的方式。

  • 如果您使用委托,则使用代码可能会以您希望阻止的方式(例如重置其调用列表)来干扰它。events不允许这种情况发生。

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

至于你的第二个问题:使用 anevent你会创建一个派生自的类EventArgs来保存数据,并在你引发它时将其传递给事件。然后消费者将可以访问它。

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

有关详细信息,请参见此处:http: //msdn.microsoft.com/en-us/library/system.eventargs.aspx