关于委托的研究
2015-11-26 15:04
330 查看
最近有朋友因为委托的问题一直受困扰,这里总结一下
好处:
1、相当于用方法作为另一方法参数(类似于C的函数指针)
2、在两个不能直接调用的方法中作为桥梁,如:在多线程中的跨线程的方法调用就得用委托
3、当不知道方法具体实现什么时使用委托,如:事件中使用委托
二、创建delegate对象,并将你想要的传递函数作为参数传入。
创建代理对象的方法:(区别是在于方法是否静态)
1、MyDelegate myDeleGate=new MyDelegate(实例名.方法名)
2、MyDelegate myDeleGate=new
MyDelegate(类名.方法名)
三、调用,上面定义的对象调用方法。
二、匿名委托(通俗讲是直接加方法体)
三、就是比较常见的也是使用最多的
一个委托可以通过+运算委托关联多个方法,叫多路广播委托(对应于单路广播委托)。
12.2rent
要是删除这个委托方法,
上面的委托定义在类外面,委托写类里这种情况跟上面的情况一样么?是有区别的
委托写在类里,就是私有的;外面拿不到。要想用就用event
这里可以看出用法其实只是加个Event其他用法还是可以一样使用的。可是我们使用的是greet不是Greet.
上面还定义一个方法 :
输出一样的结果。
这里必须使用+=运算符。
这里还有一个问题,我们把Event删了还是可以执行的,为什么呢?不是说写在类了必须要用Event么?
这里是以设计模式——观察者模式来说;
event是对委托对象的一个封装,不用event直接就可以用了,相当于一个公有的变量直接在类外面用了.破坏了封装,如果使用event,直接不能用,只能调用方法来用,这样就没有破坏封装了.
event 事件都可以用delegate来完成。event强调了事件,通过订阅事件来获得通知。
事件是针对某一个具体的对象的,一般在该对象的所属类A中写好事件,并且写好触发事件的方法,那么这个类A就是事件的发布者,然后在别的类B里面定义A的对象,并去初始化该对象的事件,让事件指向B类中的某一个具体的方法,B类就是A类事件的订阅者。当通过A类的对象来触发A类的事件的时候(只能A类的对象来触发A类的事件,别的类的对象不能触发A类的事件,只能订阅A类的事件,即实例化A类的事件),作为订阅者的B类会接收A类触发的事件,从而使得订阅函数被执行。一个发布者可以有多个订阅者,当发布者发送事件的时候,所有的订阅者都将接收到事件,从而执行订阅函数,但是即使是有多个订阅者也是单线程。
什么是委托?
委托顾名思义,就是自己不干,让别人干,这个有别与C和C++ 的函数指针(还是学过C和C++的),这里是一种方法,而且不管是静态方法还是非静态方法,而函数指针只是指向静态函数,这点也是两者的主要区别。一般委托会用在观察者模式(Observer)里。为什么要用?什么时候用委托?或者说使用委托的好处是什么呢?
说白了委托就是第三方,调用者告诉第三方要做什么,然后调用者就不用管了,这个委托(第三方)就会去调用方法去帮你实现。使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与C或C++中的函数指针不同,委托是面向对象,而且是类型安全的。好处:
1、相当于用方法作为另一方法参数(类似于C的函数指针)
2、在两个不能直接调用的方法中作为桥梁,如:在多线程中的跨线程的方法调用就得用委托
3、当不知道方法具体实现什么时使用委托,如:事件中使用委托
那么如何使用委托呢?这里总结了一下,主要分三步走;
一、定义一个委托delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。二、创建delegate对象,并将你想要的传递函数作为参数传入。
创建代理对象的方法:(区别是在于方法是否静态)
1、MyDelegate myDeleGate=new MyDelegate(实例名.方法名)
2、MyDelegate myDeleGate=new
MyDelegate(类名.方法名)
三、调用,上面定义的对象调用方法。
如何使用委托呢?也是有三种方式;
一、Labmda表达式List<int > list = new List<int> ();//定义一个list数组 list.Add (121);//添加数据 list .Add (234); list .Add (123); list .Add (123); list .Add (123); foreach (var i in list) {//遍历打印 Console.Write(i+" "); } Console.WriteLine (); list .RemoveAll ((int x) => {//定义委托指向删除方法<pre name="code" class="csharp"> if (x == 123 || x == 234) { return true; } return false; }); foreach (var i in list) {//遍历打印删除方法执行后的数组 Console.Write(i+" "); }<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
二、匿名委托(通俗讲是直接加方法体)
list.RemoveAll (delegate (int x) { if (x == 123||x==234) { return true;<pre name="code" class="csharp"> } return false; });
foreach (var i in list) { Console.Write(i+" "); }<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
三、就是比较常见的也是使用最多的
using System.Collections; using System.Collections.Generic; namespace lesson13 { delegate void myDelegate(double money);//1、定义一个参数的委托 class Host{//定义Host的类 public void sell(double money) { Console.WriteLine (money+"sell"); } } class MainClass { public static void Main (string[] args) { Host h = new Host ();//实例化 myDelegate my = h.sell;//2、定义委托对象指向方法 my(14.5);3、调用 也可以使用 my.Invoke(14.5); }显然运行结果就是14.5sell。调用委托对象的Invoke()方法,Invoke后面的括号中应包含调用该委托中的方法时使用的参数。实际上,给委托实例提供括号与调用委托类的Invoke()方法完全相同。因为Invoke()方法是委托的同步调用方法。
如何指向多个方法呢?
因为委托就是委托与相同类型方法,比如游戏里的回血回蓝啊,这样的就需要委托多个方法。一个委托可以通过+运算委托关联多个方法,叫多路广播委托(对应于单路广播委托)。
namespace ConsoleApplication1 { delegate void myDelegate(double money); class Host{ public void rent(double money) { Console.WriteLine (money+"rent"); } public void sell(double money) { Console.WriteLine (money+"sell"); } } class MainClass { public static void Main (string[] args) { Host h = new Host (); myDelegate my = h.sell; my += h.rent; my (12.2);显然结果就是12.2sell
12.2rent
要是删除这个委托方法,
my -= h.rent;显然结果就是12.2sell了。
如果方法有返回值呢?情况是不一样的。
namespace ConsoleApplication1 { delegate int SumDelegate(int x,int y);//1、定义两个参数的委托 class Host{ public int sum(int a,int b) { return a + b; } public int sum1(int a,int b) { return a + b+5; } } class MainClass { public static void Main (string[] args) { Host h = new Host ();//实例化 SumDelegate sum = h.sum; sum += h.sum1; Console.WriteLine (sum(2,3));//带返回值的委托返回最后一个 }}结果带返回值的类型在使用多路广播的时候只是打印了10=2+3+5,也就是说只是委托了最后一个。
上面的委托定义在类外面,委托写类里这种情况跟上面的情况一样么?是有区别的
委托写在类里,就是私有的;外面拿不到。要想用就用event
class Fun{ //委托写在类里,就是私有的;外面拿不到。要想用就用event public delegate void Greet(string str); public event Greet greet; public void s(string name) { greet (name); } }<pre name="code" class="csharp"> public static void Main (string[] args) { Fun fun= new Fun (); fun.greet += delegate (string name) { Console.WriteLine ("爱" + name); }; fun.s("老七");}//<pre name="code" class="csharp">结果:爱老七;给委托添加了一个打印的方法,传个值“老七”,同时也是实现了方法,就打印了。
这里可以看出用法其实只是加个Event其他用法还是可以一样使用的。可是我们使用的是greet不是Greet.
上面还定义一个方法 :
public void s1(string name) { Console.WriteLine(name + "老七"); }<pre name="code" class="csharp">public static void Main (string[] args) { Fun fun= new Fun (); fun.greet += fun.s1; fun.s1("爱");}
输出一样的结果。
这里必须使用+=运算符。
这里还有一个问题,我们把Event删了还是可以执行的,为什么呢?不是说写在类了必须要用Event么?
这里是以设计模式——观察者模式来说;
event是对委托对象的一个封装,不用event直接就可以用了,相当于一个公有的变量直接在类外面用了.破坏了封装,如果使用event,直接不能用,只能调用方法来用,这样就没有破坏封装了.
event 事件都可以用delegate来完成。event强调了事件,通过订阅事件来获得通知。
事件是针对某一个具体的对象的,一般在该对象的所属类A中写好事件,并且写好触发事件的方法,那么这个类A就是事件的发布者,然后在别的类B里面定义A的对象,并去初始化该对象的事件,让事件指向B类中的某一个具体的方法,B类就是A类事件的订阅者。当通过A类的对象来触发A类的事件的时候(只能A类的对象来触发A类的事件,别的类的对象不能触发A类的事件,只能订阅A类的事件,即实例化A类的事件),作为订阅者的B类会接收A类触发的事件,从而使得订阅函数被执行。一个发布者可以有多个订阅者,当发布者发送事件的时候,所有的订阅者都将接收到事件,从而执行订阅函数,但是即使是有多个订阅者也是单线程。
相关文章推荐
- 通过BroadcastReceiver获取SDcard,Usb连接和开机事件
- 转发与重定向
- HTTP头部详解
- 链表实现栈、队列
- [LeetCode]Minimum Height Trees
- [国嵌攻略][065][DM9000驱动程序设计]
- 终于解决了IE8不支持数组的indexOf方法,array的IndexOf方法
- SqlSessionDaoSupport与SqlSessionTemplate对比
- 程序优化——位运算
- php Spl的常用函数 链式操作
- Mongodb索引分析工具Dex 安装与使用
- 将DataGridVIew数据导出到Excel中的两种方法
- 让程序在远程主机后台运行 (&、nohuo、 screen)Linux 使用技巧
- php 一致性hash
- java读取xml文件
- LeetCode()Minimum Window Substring 超时,但觉得很清晰。
- (c++) int 转 string,char*,const char*和string的相互转换
- 在Java的Struts框架下进行web编程的入门教程
- mongo 集群时间不同步异常
- swift学习笔记-3