C#delegate v.s.事件处理程序

时间:2013-08-11 08:54:54

标签: c# delegates event-handling observer-pattern

我想在陷阱发生时向任何订阅者发送警告消息。

我使用委托方法myDelegate del创建的代码可以正常工作。

我的问题是:

  1. 我想知道使用EventHandler代替代表是否更好? 在我的案例中,我不确定委托与EventHandler之间的差异。

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

  3. 非常感谢:)

    我的代码:

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

    更新2013-08-12

    observer/observable设计模式如何,在我的案例中看起来很棒(EventHandler)。

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

    优点:

    • 不再关心GetInvocationList(),只需使用(+=)(-=)来决定向谁发送陷阱。

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

    我知道有几种方法可以做到,但我希望我能分析它的优点和缺点。

    感谢您的意见和建议,这将非常有帮助!

    我阅读了Matthew Watson建议的MSDN EventArgs文章。

    这是我的活动版本:

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

2 个答案:

答案 0 :(得分:17)

事件和委托之间的区别在于:

  

事件声明在委托实例上添加了一层保护。   此保护可防止代理的客户端重置   委托及其调用列表,只允许添加或删除   来自调用列表的目标

请参阅What are the differences between delegates and events?

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

答案 1 :(得分:8)

最好使用event作为示例。

  • Visual Studio表单和WPF设计人员可以理解event,因此您可以使用IDE订阅事件。

  • 在提出events时,您无需编写自己的foreach处理来迭代它们。

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

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

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

详情请见此处:http://msdn.microsoft.com/en-us/library/system.eventargs.aspx