委托

委托

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的权限控制

原文地址:https://www.cnblogs.com/super-xi-xi/p/10215569.html