• 委托


    委托

    1.什么是委托?

    个人理解:委托就是把一个方法当做参数传入另一个方法中进行调用。 (委托的实质就是一个类,可以通过中间语言IL编译工具去查看源码)

    2.委托的使用?

    使用委托三部曲:(1)、委托的声明 。     (2)、委托的实例化。     (3)调用。

    3.委托的种类?

    (1).delegate             (2).泛型委托 Func/ Action          (3). event 和观察者模式   

    通过delegate 关键字来声明委托 举例:

    1  public delegate void NoReturnNoPara(); // 无参数、无返回值的委托声明  
    2  public delegate void NoReturnWithPara(int x, int y);//1 声明委托
    3  public delegate int WithReturnNoPara(); //无参数、int类型返回值委托声明
    4  public delegate MyDelegate WithReturnWithPara(out int x, ref int y);//自定义委托类
    1   private void DoNothing()  //无参数无返回值的方法
    2  {
    3    Console.WriteLine("This is DoNothing 。。。。");
    4  }
    1  NoReturnNoPara method = new NoReturnNoPara(this.DoNothing);// this表示是当前类的方法,也可以把方法拆分到其他类中。这里是为了使用方便。
    2   //2 委托的实例化  要求传递一个参数类型 返回值都跟委托一致的方法,
    3  method.Invoke();//3委托实例的调用  参数和委托约束的一致

          上述三段代码,第一段是委托类型的声明; 第二段代码是为实例化委托做准备,通过实例化委托将DoNothing方法作为参数传入到委托中;第三段代码是最后调用DoNothing方法,执行DoNothing中的业务逻辑。注意:委托声明、委托的实例化 要求传递一个参数类型 返回值都跟委托一致的方法,委托实例的调用 参数和委托约束的一致。

    Action Func  .NetFramework3.0出现的

    Action 系统提供  0到16个泛型参数  不带返回值  委托

    1    //Action action = new Action(this.DoNothing);
    2     Action action0 = this.DoNothing;//是个语法糖,就是编译器帮我们添加上new Action
    3     action0.Invoke();  

    在这里的action0.invoke()和上述 method.Invoke() 执行的结果是一致的。这里推荐使用泛型委托。

    Func 委托: 无参数int类型返回值

    1  public int Get()
    2 {
    3    return 1;
    4  }
    5 
    6    //Func 系统提供  0到16个泛型参数  带泛型返回值  委托
    7   Func<int> func0 = this.Get;
    8   int iResult = func0.Invoke();

     带参数有返回值的Func委托  int类型参数,字符串类型的返回值 

    1   private string ToString(int i)
    2   {
    3     return i.ToString();
    4   }
    5   Func<int, string> func1 = this.ToString; //第一个是参数类型 ,第二个是返回值类型
    6   func1.Invoke(0); 

     多播委托

    多播委托有啥用呢?一个委托实例包含多个方法,可以通过+=/-=去增加/移除方法,Invoke时可以按顺序执行全部动作。

    多播委托:任何一个委托都是多播委托类型的子类,可以通过+=去添加方法,+= 给委托的实例添加方法,会形成方法链,Invoke时,会按顺序执行系列方法。

     1     Action method = this.DoNothing;
     2     method += this.DoNothing;
     3     method += DoNothingStatic;
     4     method += new Student().Study;
     5     method += Student.StudyAdvanced;
     6     //method.BeginInvoke(null, null);//启动线程来完成计算  会报错,多播委托实例不能异步
     7    foreach (Action item in method.GetInvocationList())
     8    {
     9     item.Invoke();
    10     //item.BeginInvoke(null, null);
    11    }

     -=  给委托的实例移除方法,从方法链的尾部开始匹配,遇到第一个完全吻合的,移除,且只移除一个,如果没有匹配,就啥事儿不发生。

    1 method -= this.DoNothing;
    2 method -= DoNothingStatic;
    3 method -= new Student().Study;//去不掉  原因是不同的实例的相同方法,并不吻合
    4 method -= Student.StudyAdvanced;
    5 method.Invoke();
    6  //中间出现未捕获的异常,直接方法链结束了

    Func 的多播委托 

    1  {
    2       Func<int> func = this.Get;
    3       func += this.Get2;
    4       func += this.Get3;
    5      int iResult = func.Invoke();
    6     //结果是3  以最后一个为准,前面的丢失了。。所以一般多播委托用的是不带返回值的
    7  }

    解决泛型委托Func多返回值问题

    举例:

     1  public class DelegateMethod
     2  {
     3         //委托声明
     4         public delegate string AddDelegate<T>(T i,T j);
     5 
     6         /// <summary>
     7         /// 
     8         /// </summary>
     9         /// <returns></returns>
    10         public string MyAdd(int k ,int j)
    11         {
    12 
    13             return k + j + " ";
    14         }
    15 
    16         public string MyFuncAdd(int k,int j)
    17         {
    18 
    19             return k + j + " ";
    20    
    21         }
    22 }
     1  {
     2         DelegateMethod Method = new DelegateMethod();
     3         List<string> list_str = new List<string>();
     4 
     5         Func<int, int, string> func = Method.MyFuncAdd;
     6         func += Method.MyFuncAdd;
    // GetInvocationList() //调用多播委托的方法列表
    7 foreach (Func<int, int, string> item in func.GetInvocationList()) 8 { 9 list_str.Add(item.Invoke(1, 3)); 10 } 11 int i = 0; 12 foreach (var item in list_str) 13 { 14 i++; 15 Console.WriteLine($"第{i} 个值是:{ item}"); 16 } 17 }

    event和观察者模式

    事件可以理解成一个特殊的委托。

    事件是无处不在的,winform无处不在---WPF---webform服务端控件/请求级事件

    为啥要用事件?事件究竟能干什么?
     事件(观察者模式)能把固定动作和可变动作分开,完成固定动作,把可变动作分离出去,由外部控制
     搭建框架时,恰好就需要这个特点,可以通过事件去分离可变动作,支持扩展

     控件事件:
     启动Form---初始化控件Button---Click事件---+=一个动作
    点击按钮--鼠标操作--操作系统收到信号--发送给程序--程序得接受信号,判断控件--登陆--
     (事件只能类的内部发生)Button类自己调用Click--肯定是触发了Click事件---登陆动作就会执行

     点击按钮--鼠标操作--操作系统收到信号--发送给程序--程序得接受信号,判断控件--支付--
     (事件只能类的内部发生)Button类自己调用Click--肯定是触发了Click事件---支付动作就会执行
     
      2次按钮操作,大部分东西都是一样的,就是具体业务不一样的,
      封装的控件就完成了固定动作--接受信号&默认动作。。。
     可变部分,就是事件---是一个开放的扩展接口,想扩展什么就添加什么
      event限制权限,避免外部乱来。

    举例: 一只猫,miao一声, 导致一系列的触发动作。(触发的动作有 狗吠,baby哭,母亲安慰baby......)

     1  public class Dog : IObject
     2 {
     3         //public Dog(int id)
     4         //{ }
     5 
     6         public void DoAction()
     7         {
     8             this.Wang();
     9         }
    10         public void Wang()
    11         {
    12             Console.WriteLine("{0} Wang", this.GetType().Name);
    13         }
    14  }
     1   public class Baby : IObject
     2 {
     3         public void DoAction()
     4         {
     5             this.Cry();
     6         }
     7 
     8         public void Cry()
     9         {
    10             Console.WriteLine("{0} Cry", this.GetType().Name);
    11         }
    12 }
     1  public class Mother : IObject
     2 {
     3         public void DoAction()
     4         {
     5             this.Wispher();
     6         }
     7         public void Wispher()
     8         {
     9             Console.WriteLine("{0} Wispher", this.GetType().Name);
    10         }
    11  }

    下面通过猫类调用执行一系列动作。

     1  public class Cat
     2 {
     3         public void Miao()
     4         {
     5             Console.WriteLine("{0} Miao", this.GetType().Name);
     6             new Dog().Wang();
     7             new Baby().Cry();
     8             new Mother().Wispher();
     9                
    10         }
    11 }

    通过上述猫类调用执行可以出后续的一系列动作对猫类过度依赖, 依赖太重,依赖了多个类型,任何类型的变化都得修改猫。职责耦合,猫不仅自己Miao 还得找各种对象执行各种动作甚至控制顺序, 任意环节增加减少调整顺序 都得修改猫,实际上不该如此,猫就是猫,只做自己的事儿,需求是猫Miao一声---触发一系列的动作---代码还指定了动作, 猫只miao一声---触发一系列动作,动作从哪里来?不管,我只负责调用。

    下面通过Action实现多播委托

     先声明一个action委托  然后Invoke调用 

    1 public Action CatMiaoAction;
     1   cat.CatMiaoAction += new Dog().Wang;
     2 3   cat.CatMiaoAction += new Baby().Cry;
     4   cat.CatMiaoAction += new Mother().Wispher;
         cat.CatMiaoAction.Invoke(); //调用

    使用Action委托调用后,cat类就是稳定的 不用做修改。可以任意扩展其他对象(不如还有一个哥哥类 执行其他的动作,只需要添加一个新的类,然后通过+=的形式将方法绑定上去就可以了),同时每个不同的类还可以自由调整执行的顺序。

    我们来继续改造上述方法 通过事件来实现委托。

    举例:

    事件event:一个委托的实例,带一个event关键字,限制权限,只允许在事件声明类里面去invoke和赋值,不允许外面,甚至子类

    1 public event Action CatMiaoActionHandler;

    1  public void MiaoEvent()
    2   {
    3     Console.WriteLine("{0} MiaoEvent", this.GetType().Name);
    4     this.CatMiaoActionHandler?.Invoke();
    5            
    6   }
     1     cat.CatMiaoActionHandler += new Dog().Wang;
     2     cat.CatMiaoActionHandler += new Mouse().Run;
     3     cat.CatMiaoActionHandler += new Baby().Cry;
     4 
     5      cat.CatMiaoActionHandler += new Mother().Wispher;
     6      cat.CatMiaoActionHandler += new Brother().Turn;
     7      cat.CatMiaoActionHandler += new Father().Roar;
     8      cat.CatMiaoActionHandler += new Neighbor().Awake;
     9      cat.CatMiaoActionHandler += new Stealer().Hide;
    10 
    11       // cat.CatMiaoActionHandler.Invoke(); 
    // 因为事件的权限限制 只能在事件声明的当前类Invoke调用 不能通过在其他类直接Invoke 所以封装了一个 MiaoEvent()方法在提供外部类使用
    12       cat.MiaoEvent();

    事件和委托的区别与联系?

    委托是一种类型,事件是委托类型的一个实例,加上了event的权限控制

  • 相关阅读:
    数据结构笔记(第三章)
    数据结构笔记(第二章)
    Java第三阶段学习(四、缓冲流)
    Java第三阶段学习(三、字符流、转换流)
    Java第三阶段学习(二、IO流--------递归,字节流Stream)
    Java学习(异常类)
    Java学习(异常类练习题)
    Java学习(JDBC java连接数据库)
    Java学习(Map接口)
    Java学习(set接口、HashSet集合)
  • 原文地址:https://www.cnblogs.com/super-xi-xi/p/10215569.html
Copyright © 2020-2023  润新知