C#复习总结4

第十三章 委托

  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
原文地址:https://www.cnblogs.com/zhuxuekui/p/4162656.html