第十三章 委托

  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. [转]构建Python+Selenium2自动化测试环境(二)

    构建Python+Selenium2自动化测试环境完成之后,就需要测试支持python的selenium的版本是否都支持在不同浏览器上运行,当前我们分别在三个最通用的浏览器上通过脚本来测试. 1.在I ...

  2. x86保护模式-七中断和异常

    x86保护模式-七中断和异常 386相比较之前的cpu   增强了中断处理能力   并且引入了 异常概念 一 80386的中断和异常 为了支持多任务和虚拟存储器等功能,386把外部中断称为中断     ...

  3. 如何解决 错误code signing is required for product type 'xxxxx' in SDK 'iOS 8.2'

    如何解决 错误code signing is required for product type 'xxxxx' in SDK 'iOS 8.2' 大家在做真机调试的时候,或许会遇到这样的问题,那如何 ...

  4. BZOJ 3518 点组计数 ——莫比乌斯反演

    要求$ans=\sum_{i=1}^n \sum_{j=1}^m (n-i)(m-j)(gcd(i,j)-1)$ 可以看做枚举矩阵的大小,然后左下右上必须取的方案数. 这是斜率单增的情况 然后大力反演 ...

  5. spring DelegatingFilterProxy的原理及运用

    DelegatingFilterProxy的原理及使用 DelegatingFilterProxy就是一个对于servlet filter的代理,用这个类的好处主要是通过Spring容器来管理serv ...

  6. ndarray:一种多维数组对象

    ndarray是一个通用的同构数据多维容器,也就是说,其中的所有元素必须是相同类型的.每个数组都有一个shape(一个表示各维度大小的元组)和一个dtype(一个用于说明数组数据类型的对象). In ...

  7. 最长递增子序列(cogs 731)

    «问题描述:给定正整数序列x1,..., xn.(1)计算其最长递增子序列的长度s.(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列.(3)如果允许在取出的序列中多次使用x1和xn,则从给 ...

  8. android开发里跳过的坑——camera调用setDisplayOrientation设置预览显示旋转无效

    问题原因,在surfaceview没有设置给camera之前调用了,所以,这个方法一定要在camera.setPreviewDisplay(surfaceHolder)这个之后,启动相机预览之前调用.

  9. Java远程调用BPS流程实现流程运行简单示例

    1.简介:略 2.背景:略 3.目的:自我学习笔记 4.实现过程 (1).画出流程图 如下: 路由活动分支下的条件语句为复杂表达式: ((account<200&&divisio ...

  10. 【HDOJ6228】Tree(树)

    题意:有一棵n个点的树,在树上的点涂色,每个点涂一种颜色,一共可以涂k种颜色, 然后把同一种颜色(比如说x)的点用最优方案连起来,在连线的边涂上x颜色,问涂k次的边最多有几条 k<=500 si ...