zoukankan      html  css  js  c++  java
  • 抛开书本,为什么出现了事件,事件与委托有什么渊源?

    抛开书本,为什么出现了事件,事件与委托有什么渊源?
    博文都是源于自己的理解,文字间流露的是不是书本那样官方的语言,望大家喜欢。

    朋友,如果你对委托没什么概念,请参阅我的上一篇博文《抛开书本,为什么需要委托,它的出现成就了什么?》

    http://www.cnblogs.com/IAmBetter/archive/2012/02/08/2342443.html

    由于时间紧,博文没有涉及到 .net框架 标准式的事件,明天会写出来。

    思路:委托---->事件存在的价值---->事件的进化---->总结

    1.参照上一篇博文
    代码如下:
    山寨版委托:

    View Code
    public delegate void CYDL(string name);
    class Program
    {
    static void Main(string[] args)
    {
    CYDL one = new CYDL(Dancing);
    one += new CYDL(Singing);
    PersonCY("Mr.w",one);
    }
    static void PersonCY(string name,CYDL one)
    {
    one(name);
    }
    static void Dancing(string name)
    {
    Console.WriteLine("{0}会跳舞",name);
    }
    static void Singing(string name)
    {
    Console.WriteLine("{0}会唱歌",name);
    }
    }



    上面是一个简单的案例,也不是正规的委托:
    正规版:

    View Code
    public delegate void CYDL(string name);
    class Program
    {
    static void Main(string[] args)
    {

    CYDL one = new CYDL(Dancing);
    one += new CYDL(Singing);
    one("Mr.w");
    }

    static void Dancing(string name)
    {
    Console.WriteLine("{0}会跳舞",name);
    }
    static void Singing(string name)
    {
    Console.WriteLine("{0}会唱歌",name);
    }
    }



    思考一个问题:我们学习到现在,几乎很少在Main函数内部 从一个类内部调用这个类的另一个方法,是吧?这也太有损面向对象这个概念了。

    现在我们把 各个方法放进不同的类里,然后再利用委托调用
    代码如下:
     

    View Code
    public delegate void CYDL(string name);
    class Person
    {
    public void PersonCY(string name, CYDL one)
    {
    one(name);
    }
    }
    class Program
    {
    static void Main(string[] args)
    {
    Person person = new Person();
    person.PersonCY("Mr.w",Dancing);//这样直接代入方法也是可以的,编译器会自动委托类型

    }

    static void Dancing(string name)
    {
    Console.WriteLine("{0}会跳舞", name);
    }
    static void Singing(string name)
    {
    Console.WriteLine("{0}会唱歌", name);
    }
    }



    <注意>
    分析下:为什么person.PersonCY("Mr.w",Dancing);//这样直接代入方法也是可以的,编译器会自动委托类型?
    利用IL指令查看:
     


    1.发现ldftn指令 把 Dancing()方法在Load堆内的地址压入了堆栈。
    2.newobj 发现 这里新建CYDL 委托类型实例
    即:这里是隐式转换成了 委托类型的。

    好了,继续进入正题,

    View Code
     static void Main(string[] args)
    {
    Person person = new Person();
    CYDL one = Dancing;
    one += Singing;
    person.PersonCY("Mr.w",one);

    }



    好了,这样就符合我们的一般的模式了,即:类的对象调用方法。
    缺点:没当 实例化一个对象,那么就有可能要改变 委托变量的绑定方法,或者重新 声明一个 委托变量two,这样是不是太麻烦了。
    面向对象的有一个封装的概念,让我们把  这个委托变量封装到类内部,让对象可以调用。

    进化1:

    View Code
    public delegate void CYDL(string name);
    class Person
    {
    public CYDL one;

    public void PersonCY(string name, CYDL one)
    {
    one(name);
    }
    }
    class Program
    {
    static void Main(string[] args)
    {
    Person person = new Person();
    person.one = Dancing;
    person.one += Singing;
    person.PersonCY("Mr.w",person.one);

    }

    static void Dancing(string name)
    {
    Console.WriteLine("{0}会跳舞", name);
    }
    static void Singing(string name)
    {
    Console.WriteLine("{0}会唱歌", name);
    }
    }



    缺点:细心的朋友可能发现了,调用PersonCY(),重复带入了one的委托变量。

    进化2:
    即:
     

    View Code
    public delegate void CYDL(string name);
    class Person
    {
    public CYDL one;

    public void PersonCY(string name)
    {
    if (one != null)//判断委托是否绑定了方法
    {
    one(name);
    }
    }
    }
    class Program
    {
    static void Main(string[] args)
    {
    Person person = new Person();
    person.one = Dancing;
    person.one += Singing;
    person.PersonCY("Mr.w");
    }

    static void Dancing(string name)
    {
    Console.WriteLine("{0}会跳舞", name);
    }
    static void Singing(string name)
    {
    Console.WriteLine("{0}会唱歌", name);
    }
    }



    但是我们知道,对于字段来说,委托类型的变量也是字段,我们通常是在访问权限上是private私有的。问题来了,如果设置了委托变量为私有的访问权限,那么
    我们如何给委托绑定方法呢?(在其他非继承类中无法调用这个变量)
    对于以往,我们对于字段的处理是使用 属性,可是 委托有没有类似于属性的东西?


    进化3:事件出场
    如下:
     

    View Code
    public delegate void CYDL(string name);
    class Person
    {
    public event CYDL one;//就这么简单,加个event

    public void PersonCY(string name)
    {
    if (one != null)//判断委托是否绑定了方法
    {
    one(name);
    }
    }
    }
    class Program
    {
    static void Main(string[] args)
    {
    Person person = new Person();
    //person.one = Dancing; 这里是赋值操作,会报错
    person.one += Singing;
    person.PersonCY("Mr.w");
    }

    static void Dancing(string name)
    {
    Console.WriteLine("{0}会跳舞", name);
    }
    static void Singing(string name)
    {
    Console.WriteLine("{0}会唱歌", name);
    }
    }



    event实质就是声明一个私有的委托,使得委托封装。
    所以对于一个私有地段,person.one = Dancing; 肯定会报错。
    查看IL代码:

     


    变量one:private class DL.CYDL 说明自动生成了一个私有的变量。所以无法使用“=”赋值。
    上图可以看出:一个委托会注册和注销方法,本质是在加载的时候加载了add_one和remove_one方法。
    本质 委托就是一个类,当执行public delegate void CYDL(string name);的时候就会生产一个完整的类。

    以上就是简单的事件的概念,可能有朋友会问 怎么和winform中的事件不一样啊?

    进化4:像样的事件
    事件有2个用户:被监视者 监视者,事件必须本身触发。
    可能难以理解,我举个例子:
    1.被监视者如果发生某种改变,监视者会根据这个改变作出相应的对策
    2.那么监视者如何知道 被监视者改变了呢,这就是注册事件。
    面向对象的设计 有 继承关系 聚合关系 依赖关系,一般OBServer模式 就是耦合度低的依赖关系。

    很形象的比如为 微博,我是博主,你们都订阅我,我发布新的微博信息了,你们就都收到了我的信息,然后对我的信息作出回应,如:转发,评论等。

    View Code
     class 微博
    {
    public delegate void 委托();
    public event 委托 事情;
    private int 数字;
    public void 数到10()
    {
    for (int i = 1; i < 100; i++)
    {
    数字 = i;//当我在博客上数到10的时候,就告诉收听我的人

    if (事情 != null)//判断是否有博友收听我的微博
    {
    if (数字 == 10)
    {
    事情();//就触发收听我的人的方法
    }
    }
    }

    }
    }

    class 博友1
    {
    public void 转发()
    {
    Console.WriteLine("我知道你数到10了,我抓发你的微博");
    }
    }

    class 博友2
    {
    public void 评论()
    {
    Console.WriteLine("我也知道你数到10了,我评论了你的微博");
    }

    }
    上面是服务端,如何触发呢?
    请看下列代码:
    class Test
    {
    static void Main()
    {
    微博 博主 = new 微博();
    博友1 one = new 博友1();
    博友2 two = new 博友2();
    博主.事情 +=new 微博.委托(one.转发);
    博主.事情 += new 微博.委托(two.评论);

    博主.数到10();

    }
    }

    总结:技术有限,有错大家指正。博文形象易懂。.net框架的标准 事件 今天来不及发布了。





  • 相关阅读:
    Bzoj_1562 [NOI2009]变换序列
    Bzoj_1443 [JSOI2009]游戏Game
    Bzoj_3572 [Hnoi2014]世界树
    【python】按顺序排列组合输出字符串
    【python】通过LibreOffice把html文件转换成docx文件
    【python】判断一个地址是ipv4还是ipv6
    【python】判断一个字符串是否是数字
    【python】ImportError: cannot import name 'QWebView'
    【python】ModuleNotFoundError: No module named 'PyQt5.QtWebKitWidgets'
    【GNS3】Error 9: Unknown boot failure
  • 原文地址:https://www.cnblogs.com/IAmBetter/p/2342800.html
Copyright © 2011-2022 走看看