【问题标题】:C# delegate v.s. EventHandlerC# 委托与事件处理程序
【发布时间】:2013-08-11 08:54:54
【问题描述】:

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

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

我的问题是:

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

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

非常感谢:)

我的代码:

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 年 8 月 12 日更新

observer/observable 设计模式怎么样,在我的情况下看起来很棒 (EventHandler)。

在我的例子中,一台机器订阅了一个陷阱信使。 (将机器添加到调用列表) 一旦发生陷阱,我会向所有订阅的机器发送一条消息。 (拨打HandleEvent处理)

优点:

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

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

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

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

我阅读了 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();
    }
}

【问题讨论】:

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


【解决方案1】:

事件和委托的区别在于:

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

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

【讨论】:

  • 所以我必须在我发布的代码中处理调用列表,对吗?
  • 你需要提供改变它的函数,而不是直接访问它。OOP封装概念
【解决方案2】:

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

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

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

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

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

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

详情请看这里:http://msdn.microsoft.com/en-us/library/system.eventargs.aspx

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-24
    相关资源
    最近更新 更多