第十三章 委托

  1. 什么是委托

    委托就是函数的指针。

其和类相似,其实就是用户自定义的引用类型。

委托是包含有序方法列表的对象,这些方法具有相同的签名和返回类型。

MyDel delvar = new MyDel(myInstObj.mym1); < == > MyDel delvar = myInstObj.mym1; //两者之间存成隐式转换。

委托 中还存在给委托赋值,这样会重新指向,组合委托等等。

委托可以添加方法也可以移除方法。 运算符: += -=

调用委托就和调用函数是一样的。

匿名方法:就是没有了 具体的的实例化后的方法名,只有函数体。

注意作用域的范围:

利用正则表达式,可以简化 委托。

 

代码如下:

  1.    delegate
    void PrintFunction();//定义一个没有返回值和参数的委托类型
  2.    delegate
    void MyDel(ref
    int x);//引用参数
  3.    class Test
  4.    {
  5.        public
    void Print1()
  6.        {
  7.            Console.WriteLine("Print1 --- instance");
  8.        }
  9.        public
    static
    void Print2()
  10.        {
  11.            Console.WriteLine("Print2 ----- static");
  12.        }
  13.        public
    void ADD2(ref
    int x)
  14.        {
  15.            x += 2;
  16.        }
  17.        public
    void ADD3(ref
    int x)
  18.        {
  19.            x += 3;
  20.        }
  21.    }
  22. //调用
  23.           //委托是指持有一个或多个方法的对象,说白了,其实就是函数指针
  24.            //也可以理解为用户自定义的引用类型
  25.             //可以把delegate看成是一个包含有序方法列表的对象,这些方法具有相同的签名和返回类型
  26.             //调用列表中的方法可以是静态方法也可以是实例方法
  27.             //一般先申明,然后创建委托对象。一般我们可以通过+=来组合委托
  28.             //MyDel delA = MyIntObj.MyM1;//都是某个方法的名称,也就是其指针了
  29.             //MyDel delB = MyIntObj.MyM2;
  30.             //MyDel delC = delA + delB;
  31.             Test test = new Test();//创建一个测试类实例
  32.             PrintFunction pf99;//创建一个空委托
  33.             pf99 = test.Print1;//实例化并初始化该委托
  34.             //也可以 pf99 = new PrintFunction(test.Print1);//可以省略
  35.             pf99 += Test.Print2;//给委托添加3个另外的方法
  36.             pf99 += test.Print1;
  37.             pf99 += Test.Print2;
  38.             if (pf99 != null)
  39.             {
  40.                 pf99();//确认委托有方法,并调用委托(无参方法)
  41.             }
  42.             else
  43.             {
  44.                 Console.WriteLine("Delegate is empty!");
  45.             }
  46.             //调用带返回值的委托方法,只需在其他方法中有返回值即可,其执行的是最后一个方法的返回值。
  47.             //调用带引用参数的委托 参数值会根据调用列表中的一个或多个方法的返回值而改变。
  48.             MyDel mydel = test.ADD2;
  49.                  mydel += test.ADD3;
  50.  
  51.             int x = 5;
  52.             mydel(ref x);
  53.  
  54.             Console.WriteLine("Value: {0}", x);
  55.  
  56.             //匿名方法
  57.             //匿名方法是初始化委托是内联声明的方法,即不需要函数了,而是在委托内部自定义函数
  58.             //匿名方法的参数列表必须在参数数量,参数类型与位置,修饰符三个方面与委托匹配。
  59.             //当然,有时候,我们也可以省略参数列表中的数据声明。params参数必须放在最后。
  60.             //delegate void Mydel(int x, params int[] y) ;
  61.             //Mydel mydel = delegate(int x, int[] y){ };
  62.             // Lambda 表达式
  63.             // Mydel mydel = delegate(int x){return x + 1};//匿名方法
  64.             // Mydel mydel = (int x) => {return x + 1}; //Lambda 表达式
  65.             // Mydel mydel = x => x + 1;

 

第十四章 事件

  1. 发布者与订阅者模式

    发布者就是数据的发送端,订阅者是数据的接收端,但是呢,订阅者必须先在发布者这一端注册才行。

     

    需要在事件中使用的代码有5个部分:

    对应的代码如下:

    //简单点理解:订阅者订阅事件,发布者触发事件,订阅者执行事件处理程序。

     

    利用系统的事件有一个好处不用自己单独在声明委托了,但是不能从发布者传递数据到订阅者去,怎么办?

    通过扩展的EventArgs来实现。其实,只需要声明一个派生自EventArgs类即可。

    代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace CsharpStart
  7. {
  8.     delegate
    void Hander();//声明委托
  9.     //发布者类
  10.     class Incrementer
  11.     {
  12.         public
    event Hander CountedADozen;//创建事件并发布 (事件是特殊的委托)
  13.         public
    void DoCount()
  14.         {
  15.             for (int i = 0; i < 100; i++) //事件调用函数,或者称为触发事件函数
  16.             {
  17.                 if (i % 12 ==0 && CountedADozen != null)
  18.                 {
  19.                     CountedADozen();//每增加12,事件触发一次
  20.                 }
  21.             }
  22.         }
  23.     }
  24.     //订阅者类
  25.     class Dozens
  26.     {
  27.         public
    int DozensCount { get; private
    set; }
  28.  
  29.         public Dozens(Incrementer incrementer)//以发布者类为参数
  30.         {
  31.             DozensCount = 0;
  32.             incrementer.CountedADozen += IncrementerDozensCount;//订阅事件(为事件CountedADozen增加方法)
  33.         }
  34.         void IncrementerDozensCount()
  35.         {
  36.             DozensCount++; //声明事件处理程序
  37.         }
  38.     }
  39.  
  40. //系统自带的委托类型
  41.     public
    delegate
    void EventHandler(object sender, EventArgs e);
  42. //其中,第一个参数是用来保存触发事件的对象的引用。
  43.     //第二个参数用来保存状态信息,指明什么类型适用于该程序。
  44.   //用系统自带的委托的话,就不需要自定义委托类型了
  45.     //发布者类
  46.     class Incrementer1
  47.     {
  48.         public
    event EventHandler CountedADozen1;//创建事件并发布 (事件是特殊的委托)
  49.         public
    void DoCount()
  50.         {
  51.             for (int i = 0; i < 100; i++) //事件调用函数,或者称为触发事件函数
  52.             {
  53.                 if (i % 12 == 0 && CountedADozen1 != null)
  54.                 {
  55.                     CountedADozen1(this,null);//每增加12,事件触发一次
  56.                                               //触发事件时使用EventHandler的参数
  57.                 }
  58.             }
  59.         }
  60.     }
  61.     //订阅者类
  62.     class Dozens1
  63.     {
  64.         public
    int DozensCount1 { get; private
    set; }
  65.  
  66.         public Dozens1(Incrementer1 incrementer1)
  67.         {
  68.             DozensCount1 = 0;
  69.             incrementer1.CountedADozen1 += IncrementerDozensCount1;//订阅事件
  70.         }
  71.         void IncrementerDozensCount1(object sender,EventArgs e)//事件处理程序的签名(特征)
  72.                                                          //必须和系统的委托的签名相匹配
  73.         {
  74.             DozensCount1++; //声明事件处理程序
  75.         }
  76.     }
  77.  
  78.   //如何传递数据到事件处理程序中
  79.     public
    class IncrementerEventArgs : EventArgs
  80.     {
  81.         public
    int IterationCount { get; set; }
  82.     }
  83.  
  84.     class Incrementer2
  85.     {
  86.         public
    event EventHandler<IncrementerEventArgs> CountedADozen2;//使用自定义类的泛型委托
  87.  
  88.         public
    void DoCount2()
  89.         {
  90.             IncrementerEventArgs args = new IncrementerEventArgs();//使用自定义的类对象
  91.             for (int i = 0; i < 100; ++i)
  92.             {
  93.                 if (i % 12 == 0 && CountedADozen2 != null)
  94.                 {
  95.                     args.IterationCount = i;//携带的参数
  96.                     CountedADozen2(this, args);//可以理解为sendmessage
  97.                 }
  98.             }
  99.         }
  100.     }
  101.  
  102.     class Dozens2
  103.     {
  104.         public
    int DozensCount2 { get; set; }
  105.         public Dozens2(Incrementer2 incrementer)
  106.         {
  107.             DozensCount2 = 0;
  108.             incrementer.CountedADozen2 += IncrementDozensCount;//订阅事件
  109.         }
  110.         public
    void IncrementDozensCount(object sender, IncrementerEventArgs e)//事件处理程序
  111.         {
  112.             Console.WriteLine("Incremented at iteration : {0} in {1}",e.IterationCount,sender.ToString());
  113.             DozensCount2++;
  114.         }
  115.     }
  116. }
  117.  
  118. //调用
  119.  //1、发布者/订阅者模式,当一个特定的程序事件发生时,程序的其他部分可以得到该事件
  120.             //已经发生了的通知,并执行相应的 事件处理程序。调用(invoke)
  121.             //5个部分: 1)声明委托。 发布者: 2)创建事件并发布 3)触发事件
  122.             // 订阅者: 4)订阅事件 5)事件处理程序
  123.             Incrementer incrementer = new Incrementer(); //实例化
  124.             Dozens dozensCounter = new Dozens(incrementer);
  125.             incrementer.DoCount();//触发事件,调用事件。
  126.             Console.WriteLine("Number of dozens = {0}",dozensCounter.DozensCount);
  127.             //2、使用系统定义的EventHandler委托
  128.             Incrementer1 incrementer1 = new Incrementer1(); //实例化
  129.             Dozens1 dozensCounter1 = new Dozens1(incrementer1);
  130.             incrementer1.DoCount();//触发事件,调用事件。
  131.             Console.WriteLine("Number of dozens1 = {0}", dozensCounter1.DozensCount1);
  132.             //3、通过扩展的EventArgs来传递数据,简单的说就是通过派生类来实现
  133.             Incrementer2 incrementer2 = new Incrementer2();
  134.             Dozens2 dozensCounter2 = new Dozens2(incrementer2);//实例化
  135.             incrementer2.DoCount2();//触发事件
  136.  
  137.             //4、我们还可以通过 -= 来移除事件。
  138.             //我们在添加事件的时候,不仅仅可以从构造方法中添加(订阅)事件,也可以
  139.             //在实例化后,在main函数中订阅事件。
  140.  
  141.             //5、事件访问器 我们可以为事件定义事件访问器 add与remove

C#复习总结4的更多相关文章

  1. iOS总结_UI层自我复习总结

    UI层复习笔记 在main文件中,UIApplicationMain函数一共做了三件事 根据第三个参数创建了一个应用程序对象 默认写nil,即创建的是UIApplication类型的对象,此对象看成是 ...

  2. vuex复习方案

    这次复习vuex,发现官方vuex2.0的文档写得太简略了,有些看不懂了.然后看了看1.0的文档,感觉很不错.那以后需要复习的话,还是先看1.0的文档吧.

  3. 我的操作系统复习——I/O控制和系统调用

    上篇博客介绍了存储器管理的相关知识——我的操作系统复习——存储器管理,本篇讲设备管理中的I/O控制方式和操作系统中的系统调用. 一.I/O控制方式 I/O就是输入输出,I/O设备指的是输入输出设备和存 ...

  4. 复习(1)【Maven】

    终于开始复习旧知识了,有输入必然要有输出.输入和输出之间的内化过程尤为重要,在复习的同时,真正把学到的东西积淀下来,加深理解. Maven项目概念与配置 Maven是一个项目管理和综合工具.Maven ...

  5. 《CSS权威指南》基础复习+查漏补缺

    前几天被朋友问到几个CSS问题,讲道理么,接触CSS是从大一开始的,也算有3年半了,总是觉得自己对css算是熟悉的了.然而还是被几个问题弄的"一脸懵逼"... 然后又是刚入职新公司 ...

  6. JS复习--更新结束

    js复习-01---03 一 JS简介 1,文档对象模型 2,浏览器对象模型 二 在HTML中使用JS 1,在html中使用<script></script>标签 2,引入外部 ...

  7. jQuery 复习

    jQuery 复习 基础知识 1, window.onload $(function(){});   $(document).ready(function(){}); 只执行函数体重的最后一个方法,事 ...

  8. jQuery5~7章笔记 和 1~3章的复习笔记

    JQery-05 对表单和表格的操作及其的应用 JQery-06 jQuery和ajax的应用 JQery-07 jQuery插件的使用和写法 JQery-01-03 复习 之前手写的笔记.实在懒得再 ...

  9. HTML和CSS的复习总结

    HTML(Hypertext Markup Language)超文本标记语言:其核心就是各种标记!<html> HTML页面中的所有内容,都在该标签之内:它主要含<head>和 ...

  10. 2017年1月1日 java学习第二天复习

    今天是新年的第一天,以前学习没有总结习惯,学习效率和成果都很不好.  学习的过程就是反复的复习和不断学习的过程,开始今天的学习总结   学习java的第二天. 今天学习了java最基础的一些内容,照着 ...

随机推荐

  1. cocos2d中的anchorPoint属性详解

    原文地址:http://www.tuicool.com/articles/ANVjMj 1> anchorPoint对position的影响 anchorPoint的作用就是相当于确定在子节点的 ...

  2. mysql 面安装配置

    解压MySQL压缩包    将以下载的MySQL压缩包解压到自定义目录下,我的解压目录是:    "D:\Program Files\MySQL\mysql-5.6.13-win32&quo ...

  3. 【RAID】raid1 raid2 raid5 raid6 raid10的优缺点和做各自raid需要几块硬盘

    Raid 0:一块硬盘或者以上就可做raid0优势:数据读取写入最快,最大优势提高硬盘容量,比如3快80G的硬盘做raid0 可用总容量为240G.速度是一样.缺点:无冗余能力,一块硬盘损坏,数据全无 ...

  4. 【13】javascript跨域通信

    javascript跨域通信 同源:两个文档同源需满足 协议相同 域名相同 端口相同 跨域通信方法: 01,通过设置img,script,link,iframe元素的src,href属性为目标url. ...

  5. Wp8无广告 锁屏可以持续用的手电筒

    前面的博文写了怎么实现手电筒,界面不够漂亮 我修改了界面之后 提交到了微软的App商店 在这里送上下载地址: http://www.windowsphone.com/zh-cn/store/app/% ...

  6. 【drp 12】再识转发和重定向:SpringMVC无法跳转页面

    最近再使用SpringMVC进行页面跳转的时候,不知道发生了什么,始终都无法正确跳转.后来问题解决了,发现是对于转发和重定向没有能很好的理解,以此写篇博客,权当做积累了! 声明:本博客的所有代码,均为 ...

  7. Codeforces 547B. Mike and Feet[单调栈/队列]

    这道题用单调递增的单调栈维护每个数能够覆盖的最大区间即可. 对于   1 2 3 4 5 4 3 2 1 6 这组样例, 1能够覆盖的最大区间是10,2能够覆盖的最大区间是7,以此类推,我们可以使用单 ...

  8. iOS代理转移

    在控制器里面想调用一个视图的子视图的代理方法很简单 1.找到子视图的协议和代理属性 2.给你想调用的控件添加代理属性,遵守的协议和子视图的一样 3.重写代理属性的set方法

  9. Opencv学习笔记——视频进度条的随动

    1. CvCapture结构体: CvCapture是一个结构体,用来保存图像捕获的信息,就像一种数据类型(如int,char等)只是存放的内容不一样,在OpenCv中,它最大的作用就是处理视频时(程 ...

  10. USACO Party Lamps

    题目大意:一排灯有n个,有4种开关,每种开关能改变一些灯现在的状态(亮的变暗,暗的变亮)现在已知一些灯的亮暗情况,问所以可能的情况是哪些 思路:同一种开关开两次显然是没效果的,那么枚举每个开关是否开就 ...