zoukankan      html  css  js  c++  java
  • 复习一下 .Net: delegate(委托)、event(事件) 的基础知识,从头到尾实现事件!

    有这样一道 .Net/C# 面试题:
    请以事件的概念实现: 控制台屏幕录入任意字符串,并回显 "你键入了:" + 你刚才键入的字符串,如果键入 "q",退出程序,运行结束!
    .Net 的 delegate 与 event 的实现是不可分的!属于基础知识!
    写惯了 Windows 下的事件响应程序,真正从头到尾实现事件不常见!
    我有两篇老文章:
    《C# 写的 HttpRequsetResponse 类,异步、事件... 还热乎着呢!》
    http://www.csdn.net/Develop/read_article.asp?id=19254
    http://blog.csdn.net/playyuer/archive/2003/07/03/2856.aspx
    《TreeView 的派生类: TreeViewEx 实现 NodeShowToolTip、NodeDoubleClick 事件》
    http://www.csdn.net/Develop/Read_Article.asp?Id=19246
    http://blog.csdn.net/playyuer/archive/2003/06/26/2857.aspx
    也只是在 WinForm 下部分的实现了事件处理!而不是事件的触发
    我的最简单的参考答案,都是用 static 方法实现的:
    class Class1
    {
        
    public delegate void FireEventHandler(string s);
        
    public static event FireEventHandler FireStatic;
        
    static bool b = false;
        
    static void Main(string[] args)
        
    {
            FireStatic 
    += new FireEventHandler(Fire1);
            System.Console.WriteLine(
    "请键入任意字符(串),\"q\" 退出!");
            
    string s;
            
    while (true)
            
    {
                s 
    = System.Console.ReadLine();
                FireStatic(s);
                
    if (b == true)
                
    break;
            }

        }

        
    static void Fire1(string s)
        
    {
            
    if (s != "q")
            
    {
                System.Console.WriteLine(
    "你键入了: " + s);
            }

            
    else
            
    {
                System.Console.WriteLine(
    "不送了!");
                b 
    = true;
            }

        }

    }

    经常编写 WinForm 程序的人应该熟悉,我想应该还是有人()不知道具体怎样实现的事件!
    这些人实际并不一定真知道:
    this.button1.Click += new System.EventHandler(this.button1_Click)
    EventHandler 到底是怎么实现的?不过这确实不妨碍编写 Click 事件的响应代码!

    今天我也复习了一下,提炼出 C# Console 程序跟大家分享一下:
    请一定要注意程序注释,运行时注意屏幕提示:

    // 请存为任意 *.cs 文件后,csc 成 exe 文件!
    class Class1
    {
        
    //声明一个委托 delegate FireEventHandler,delegate 没有 静态或实例 成员的说法
        public delegate void FireEventHandler(string s);

        
    //声明 FireEventHandler 委托类型的事件
        
    //亦即将 FireEventHandler 理解为数据类型,易理解
        public event FireEventHandler FireInstance;
        
    public static event FireEventHandler FireStatic;

        
    static void Main(string[] args)
        
    {
            System.Console.WriteLine(
    "Hello World");

            
    //用 delegate: FireEventHandler() 委托,建立委托关系
            
    //Static 方法 FireStatic() 代理(被委托)了 Static 方法 Fire1()
            FireStatic += new FireEventHandler(Fire1);
            
    //Static 方法 FireStatic() 代理(被委托)了 Instance 方法 .Fire2()
            FireStatic = FireStatic + new FireEventHandler(new Class1().Fire2);

            Class1 c 
    = new Class1();

            
    //Instance 方法 .FireInstance() 代理(被委托)了 Instance 方法 .Fire2()
            c.FireInstance += new FireEventHandler(c.Fire2);

            
    //Instance 方法 .FireInstance() 代理(被委托)了 Static 方法 Fire1()
            c.FireInstance = new FireEventHandler(Fire1) + c.FireInstance;
            
    //以上仅是声明了委托关系,尚未执行 委托代理方法 !

            System.Console.WriteLine(
    "下面列印委托关系:");
            System.Console.WriteLine(
    "Static 方法 FireStatic() 作为代理接受以下委托:");

            ListDelegateRelation(FireStatic);

            System.Console.WriteLine();

            System.Console.WriteLine(
    "Instance 方法 .FireInstance() 作为代理接受以下委托:");
            ListDelegateRelation(c.FireInstance);

            System.Console.WriteLine(
    "请键入任意字符(串),\"q\" 退出!");
            
    string s;
            
    while (true)
            
    {
                s 
    = System.Console.ReadLine();
                System.Console.WriteLine(
    "--------------------------");
                System.Console.WriteLine(
    "以下是键入 \"{0}\" 后,触发事件的响应:");
                
    //我们在此编程,即:在接受屏幕行录入后,令程序执行委托代理方法!
                
    //从而触发了事件!
                
    // FireStatic 静态事件被触发了
                FireStatic("FireStatic 静态事件被触发了:\nStatic 方法 FireStatic() 受委托代理执行了 {0}\n你键入了: [" + s + "]\n");

                
    // .FireInstance 实例事件被触发了
                c.FireInstance(".FireInstance 实例事件被触发了: \nInstance 方法 .FireInstance() 受委托代理执行了 {0}\n你键入了: [" + s + "]\n");
                System.Console.WriteLine(
    "=======================================");
                System.Console.WriteLine(
    "请键入任意字符(串),\"q\" 退出!");
                
    if (s == "q")
                    
    break;
            }

            
    ///*
            //解除委托关系可用 "-="
            
    //下面解除委托,列印剩余委托关系
            ListDelegateRelation(FireStatic);

            FireStatic 
    -= new FireEventHandler(Fire1);
            ListDelegateRelation(FireStatic);

            FireStatic 
    = FireStatic - new FireEventHandler(new Class1().Fire2);
            ListDelegateRelation(FireStatic);

            c.FireInstance 
    = new FireEventHandler(Fire1) - c.FireInstance;
            ListDelegateRelation(c.FireInstance);

            c.FireInstance 
    = c.FireInstance - new FireEventHandler(Fire1);
            ListDelegateRelation(c.FireInstance);
        }


        
    //静态方法
        static void Fire1(string s)
        
    {
            
    //响应事件的程序
            System.Console.WriteLine(s.Replace("{0}","static 方法 Fire1()"));
        }


        
    //实例方法
        void Fire2(string s)
        
    {
            
    //响应事件的程序
            System.Console.WriteLine(s.Replace("{0}","Instance 方法 .Fire2()"));
        }


        
    static void ListDelegateRelation(FireEventHandler x)
        
    {
            
    if (x != null)
            
    {
                
    //   foreach (System.Delegate d in x.GetInvocationList())
                foreach (FireEventHandler d in x.GetInvocationList())
                
    {
                    System.Console.WriteLine(x.ToString() 
    + " 类型的事件代理了 " + (d.Method.IsStatic ? x.Target + " 类的 Static 方法 ":d.Target + " 的 Instance 方法 .")  + d.Method.Name);
                }

            }

            
    else
            
    {
                System.Console.WriteLine(
    "没有任何委托关系");
            }

        }

    }


    下面是一个更复杂点的 Console 程序,根据 输入数字的奇偶性触发不同的事件!

    using System.Text.RegularExpressions;
    class Class1
    {
        
    private static Class1 x;
        
    static void Main(string[] args)
        
    {
            System.Console.WriteLine(
    "Hello World");
            x 
    = new Class1();

            
    //设置委托 delegate 关系
            
    //把 += 右边的 委托 给左边 的 (-= 是取消委托关系)
            
    //以后就可以用对"左边"的方法签名的调用,实际就是相当于调用了"右边"的方法的执行
            
    //将 Class1 的实例方法(x.Fire1) 委托给 Class1 的实例事件(x.FireInstance)
            x.FireInstance += new Class1.FireEventHandler(x.Fire1);

            
    //将 Class1 的静态方法(Class1.Fire2) 委托给 Class1 的实例事件(x.FireInstance)
            x.FireInstance += new Class1.FireEventHandler(Class1.Fire2);

            
    //将 Class1 的静态方法(Class1.Fire2) 委托给 Class1 的静态事件(Class1.FireStatic)
            Class1.FireStatic += new Class1.FireEventHandler(Class1.Fire3);

            
    //将 Class1 的实例方法(x.Fire1) 委托给 Class1 的静态事件(Class1.FireStatic)
            Class1.FireStatic += new Class1.FireEventHandler(x.Fire4);

            
    int i;
            
    string s;
            
    while (true)
            
    {
                
    if ((s = System.Console.ReadLine()) == "q")
                
    {
                    
    break;
                }

                
    if (Regex.IsMatch(s,@"^\d+$"))
                
    {
                    i 
    = System.Convert.ToInt32(s);
                    
    if (i % 2 == 0)
                    
    {
                        
    //输入时偶数触发该事件
                        x.OnFireInstance();//调用实例方法触发事件
                    }

                    
    else
                    
    {
                        
    //输入时基数触发该事件
                        Class1.OnFireStatic(); //调用静态方法触发事件
                    }

                }

            }

        }

        
    public string Fire1() //实例方法
        {
            System.Console.WriteLine(
    "输入是偶数");
            
    return null;
        }

        
    public static string Fire2() //静态方法
        {
            System.Console.WriteLine(
    "输入是偶数");
            
    return null;
        }

        
    public static string Fire3() //静态方法
        {
            System.Console.WriteLine(
    "输入是奇数");
            
    return null;
        }

        
    public string Fire4() //实例方法
        {
            System.Console.WriteLine(
    "输入是奇数");
            
    return null;
        }


        
    //大多数委托是不需要返回值!

        
    public delegate string FireEventHandler();
        
        
    //实例事件
        public event FireEventHandler FireInstance;

        
    //静态事件
        public static event FireEventHandler FireStatic;

        
    //实例方法
        public void OnFireInstance()
        
    {
            
    //实例方法触发实例事件
            
    //根据委托关系的声明:
            
    //委托执行时: 将实际调用执行 Fire1 和 Fire2
            this.FireInstance(); //实例方法触发实例事件 委托执行
            System.Console.WriteLine("以下是错误答案: 仅是测试\"实例方法\"触发\"静态事件\"");
            
    //实例方法触发静态事件
            
    //根据委托关系的声明:
            
    //委托执行时: 将实际调用执行 Fire3 和 Fire4
            FireStatic(); //实例方法触发静态事件 委托执行
        }


        
    //静态方法
        public static void OnFireStatic()
        
    {
            
    //静态方法触发静态事件 
            
    //根据委托关系的声明:
            
    //委托执行时: 将实际调用执行 Fire3 和 Fire4
            FireStatic();

            System.Console.WriteLine(
    "以下是错误答案: 仅是测试\"静态方法\"触发\"实例事件\"");
            
    //实例成员 x 就是为这里调用实例事件方法!
            
    //静态方法触发实例事件 
            
    //根据委托关系的声明:
            
    //委托执行时: 将实际调用执行 Fire1 和 Fire2
            x.FireInstance(); //静态方法触发实例事件 委托执行
        }

    }

    -- 回答下面网友问题
    -- 仿 Windows 的事件, 用 Console 实现,也许有助于你记忆
    -- 拥有事件的类在一个单独的类中! 类似于 WinForm Button

    //=======================================
    //static 方法挂接事件
    class AppTest
    {
        
    static void Main(string[] args)
        
    {
            WithEventsClass.FireStatic 
    += new WithEventsClass.FireEventHandler(Fire1);
            System.Console.WriteLine(
    "请键入任意字符(串),\"q\" 退出!");
            WithEventsClass.Run();
        }

        
    // static
        static void Fire1(string s)
        
    {
            
    if (s != "q")
            
    {
                System.Console.WriteLine(
    "你键入了: " + s);
            }

            
    else
            
    {
                System.Console.WriteLine(
    "不送了!");
                WithEventsClass.b 
    = true;
                WithEventsClass.FireStatic 
    -= new WithEventsClass.FireEventHandler(Fire1);
            }

        }

    }


    class WithEventsClass
    {
        
    public delegate void FireEventHandler(string s);
        
    public static event FireEventHandler FireStatic;
        
    public static bool b = false;
        
    public static void Run()
        
    {
            
    string s;
            
    while (!b)
            
    {
                s 
    = System.Console.ReadLine();
                
    if (FireStatic != null)
                
    {
                    FireStatic(s);
                }

            }

        }

    }
    //=======================================
    //instance1 方法挂接事件
    class AppTest
    {
        
    public WithEventsClass _wec;
        
    static void Main(string[] args)
        
    {
            AppTest a 
    = new AppTest();
            WithEventsClass wec 
    = new WithEventsClass();

            wec.FireInstance 
    += new WithEventsClass.FireEventHandler(a.wec_FireInstance);
            a._wec 
    = wec;
            System.Console.WriteLine(
    "请键入任意字符(串),\"q\" 退出!");
            wec.Run();

        }

        
    private void wec_FireInstance(string s)
        
    {
            
    if (s != "q")
            
    {
                System.Console.WriteLine(
    "你键入了: " + s);
            }

            
    else
            
    {
                System.Console.WriteLine(
    "不送了!");
                _wec.b 
    = true;
                _wec.FireInstance 
    -= new WithEventsClass.FireEventHandler(this.wec_FireInstance);
            }

        }

    }


    class WithEventsClass
    {
        
    public delegate void FireEventHandler(string s);
        
    public event FireEventHandler FireInstance;
        
    public bool b = false;
        
    public void Run()
        
    {
            
    string s;
            
    while (!this.b)
            
    {
                s 
    = System.Console.ReadLine();
                
    if (this.FireInstance != null)
                
    {
                    
    this.FireInstance(s);
                }

            }

        }

    }

    //=================================================
    //instance2 方法挂接事件,拥有事件的类在一个单独的类中! 类似于 WinForm Button
    class AppTest
    {
        
    static void Main(string[] args)
        
    {
            AppTest a 
    = new AppTest();
            WithEventsClass wec 
    = new WithEventsClass();
            wec.FireInstance 
    += new WithEventsClass.FireEventHandler(a.wec_FireInstance);
            System.Console.WriteLine(
    "请键入任意字符(串),\"q\" 退出!");
            wec.Run();
        }

        
    //类似于 Click
        private void wec_FireInstance(WithEventsClass Sender)
        
    {
            
    if (Sender.s != "q")
            
    {
                System.Console.WriteLine(
    "你键入了: " + Sender.s);
            }

            
    else
            
    {
                System.Console.WriteLine(
    "不送了!");
                Sender.b 
    = true;
                Sender.FireInstance 
    -= new WithEventsClass.FireEventHandler(this.wec_FireInstance);
            }

        }

    }


    class WithEventsClass
    {
        
    public delegate void FireEventHandler(WithEventsClass Sender);
        
    public event FireEventHandler FireInstance;
        
    public bool b = false;
        
    public string s;
        
    public void Run()
        
    {
            
    while (!this.b)
            
    {
                
    this.s = System.Console.ReadLine();
                
    if (this.FireInstance != null)
                
    {
                    
    this.FireInstance(this);
                }

            }

        }

    }

  • 相关阅读:
    Python之位移操作符所带来的困惑
    SR采用PubSubHubbub协议实时接收GReaderSharedItems更新
    如何找到正在热传的微博客图片?
    手持设备:懒人的互联网音乐智能同步/播放器
    七十二般变化解得了三灾?
    如何测量Google Reader用户的分享活跃度
    基于Google Reader发展起来的个性化推荐系统之三大问题
    Python检测Windows剩余磁盘空间
    Python 内部类,内部类调用外部类属性,方法
    禁止IE页面自动跳转到EDGE浏览器的方法
  • 原文地址:https://www.cnblogs.com/Microshaoft/p/164753.html
Copyright © 2011-2022 走看看