zoukankan      html  css  js  c++  java
  • Delegate学习笔记之事件订阅

    限制只允许一个客户端注册。此时怎么做呢?我们可以向下面这样,将事件声明为private的,然后提供两个方法来进行注册和取消注册:

    // 定义事件发布者
    public class Publishser {
        private event GeneralEventHandler NumberChanged;    // 声明一个私有事件
        // 注册事件
        public void Register(GeneralEventHandler method) {
            NumberChanged = method;
        }
        // 取消注册
        public void UnRegister(GeneralEventHandler method) {
            NumberChanged -= method;
        }

        public void DoSomething() {
            // 做某些其余的事情
            if (NumberChanged != null) {    // 触发事件
                string rtn = NumberChanged();
                Console.WriteLine("Return: {0}", rtn);      // 打印返回的字符串,输出为Subscriber3
            }
        }
    }

    NOTE:注意上面,在UnRegister()中,没有进行任何判断就使用了NumberChanged-=method语句。这是因为即使method方法没有进行过注册,此行语句也不会有任何问题,不会抛出异常,仅仅是不会产生任何效果而已。

    注意在Register()方法中,我们使用了赋值操作符“=”,而非“+=”,通过这种方式就避免了多个方法注册。上面的代码尽管可以完成我们的需要,但是此时大家还应该注意下面两点:

    1、将NumberChanged声明为委托变量还是事件都无所谓了,因为它是私有的,即便将它声明为一个委托变量,客户端也看不到它,也就无法通过它来触发事件、调用订阅者的方法。而只能通过Register()和UnRegister()方法来注册和取消注册,通过调用DoSomething()方法触发事件

    我们还应该发现,这里采用的、对NumberChanged委托变量的访问模式和C#中的属性是多么类似啊?大家知道,在C#中通常一个属性对应一个类型成员,而在类型的外部对成员的操作全部通过属性来完成。尽管这里对委托变量的处理是类似的效果,但却使用了两个方法来进行模拟,有没有办法像使用属性一样来完成上面的例子呢?答案是有的,C#中提供了一种叫事件访问器(Event Accessor)的东西,它用来封装委托变量。如下面例子所示:

    class Program {
        static void Main(string[] args) {
            Publishser pub = new Publishser();
            Subscriber1 sub1 = new Subscriber1();
            Subscriber2 sub2 = new Subscriber2();

            pub.NumberChanged -= sub1.OnNumberChanged;  // 不会有任何反应
            pub.NumberChanged += sub2.OnNumberChanged;  // 注册了sub2
            pub.NumberChanged += sub1.OnNumberChanged;  // sub1将sub2的覆盖掉了
           
            pub.DoSomething();          // 触发事件
        }
    }

    // 定义委托
    public delegate string GeneralEventHandler();

    // 定义事件发布者
    public class Publishser {
        // 声明一个委托变量
        private GeneralEventHandler numberChanged;
        // 事件访问器的定义
        public event GeneralEventHandler NumberChanged {
            add {
                numberChanged = value;
            }
            remove {
                numberChanged -= value;
            }
        }
       
        public void DoSomething() {
            // 做某些其他的事情
            if (numberChanged != null) {    // 通过委托变量触发事件
                string rtn = numberChanged();
                Console.WriteLine("Return: {0}", rtn);      // 打印返回的字符串
            }
        }
    }

    // 定义事件订阅者
    public class Subscriber1 {
        public string OnNumberChanged() {
            Console.WriteLine("Subscriber1 Invoked!");
            return "Subscriber1";
        }
    }
    public class Subscriber2 {/* 与上类同,略 */}
    public class Subscriber3 {/* 与上类同,略 */}

    上面代码中类似属性的public event GeneralEventHandler NumberChanged {add{...}remove{...}}语句便是事件访问器。使用了事件访问器以后,在DoSomething方法中便只能通过numberChanged委托变量来触发事件,而不能NumberChanged事件访问器(注意它们的大小写不同)触发,它只用于注册和取消注册。下面是代码输出:

    Subscriber1 Invoked!
    Return: Subscriber1

  • 相关阅读:
    调用DirectX进行简单的多媒体编程系列(一)
    C#中编写sqlserver中自定义函数,实现复杂报表
    学习笔记:javascript定义类的过程(类一词是形象说法,javascript中并没有类一词)
    HttpModule与HttpHandler详解 (转)
    asp.net运行原理(转)
    最近项目报表开发中写的存储过程学生综合成绩对比
    调用DirectX进行简单的多媒体编程系列(四)
    清欠率(存储过程)
    ExtJS中的面向对象设计,组件化编程思想
    ExtJS中如何扩展自定义的类
  • 原文地址:https://www.cnblogs.com/johnwonder/p/1674786.html
Copyright © 2011-2022 走看看