委托的概念
委托实际上是类(一个貌似函数一样的类),我们已经使用函数指针很多年了——函数指针也被称为过程类型,但是它们的实现都不是类。它们是单独的函数指针的简单实例。委托是包含这些功能的类,委托类通过保留的列表来确定某些事物是否已经指派给了委托,这种算法可以理解为:“对于内部列表中的每一个回调函数,都调用函数”。委托除了支持回调函数外,还可以通过该列表来实现多播(委托链)。
说白了,就是我们把一批具有相同特征的方法,通过建立与具有同样相同特征的委托的一个实例来进行传递,以使其它地方能对这些方法进行调用。即把方法当作参数进行传递(浅显的认识,勿笑)。
初识委托
示例1:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Web;
namespaceMyDelegateTest
{
///<summary>
///说明:一个简单的委托示例
///作者:文野
///联系:stwyhm.cnblogs.com
///</summary>
//新建一个用以输出消息的委托
publicdelegatevoidWriteMessage();
publicclassWriteToWeb
{
//一个输出消息的静态方法
publicstaticvoidStaticWrite()
{
HttpContext.Current.Response.Write("委托调用了一个静态方法。<br />");
}
//一个输出消息的类实例方法
publicvoidWrite()
{
HttpContext.Current.Response.Write("委托调用了一个类实例方法。<br />");
}
}
}
调用:
protectedvoidPage_Load(objectsender,EventArgse)
{
//新建一个委托,回调函数是一个静态方法
WriteMessagewm =newWriteMessage(WriteToWeb.StaticWrite);
WriteToWebw =newWriteToWeb();
//新建一个委托并与加到先前建立的委托组成委托链,回调函数是一个类实例方法
wm +=newWriteMessage(w.Write);
//执行委托链上所有的回调函数
wm();
}
上面的示例程序首先建立了一个简单得不能再简单的用以输出的委托,下面的类中有两个与委托签名一致的方法(一个静态方法,一个类实例方法)。下面的调用过程首先建立了一个使用回调静态方法的委托,其后又建立了一个使用类实例方法的委托并与先前的委托组成了一个委托链,最后执行委托链上所有的方法。
由此可见,委托最简单的理解就是利用与方法签名一致的委托,可以把方法当作参数一样来传递,无论是静态方法还是类实例方法。
委托的秘密
从上面的类视图中我们看到,对委托的定义最终被编译成一个类,这个类中定义有4种方法:构造器,Invoke,BeginInvoke,EndInvoke。
所有的委托都继承自MulticastDelegate,而MulticastDelegate又继续至Delegate。这样我们定义的委托自然也就继承了MulticastDelegate的字段、属性和方法。在继承得到的所有成员中,有3个最重要的字段:
1、_target:指向调用回调函数时应该操作的对象。该字段用于实例方法的回调。
2、_methodPtr:一个内部的整数值,CLR用它来识别回调的方法。
3、_prev:指向另一个委托对象。
当编译器知道我们在构造的是一个委托时,它会分析源代码来确定要引用哪个对象和方法。其中对象引用会被传递给_target(对于静态方法,_target被置为null),一个特殊的标识方法的Int32值会被传递给_methodPtr,_prev在构造器中被置为null,它被用于在委托链中记录下一个委托的引用。
每个委托对象实际上是对方法及其调用操作的一个包装,MulticastDelegate中定义了两个只读属性,Target和Method,Target(其实就是前面的_target字段)属性返回一个方法回调时操作的对象的引用,Method属性返回一个标识回调方法的System.Reflection.MethodInfo对象。
委托链
前面介绍过MulticastDelegate中有一个_prev的私有字段,这个字段指向另一个MulticastDelegate对象的引用,这样就实现了委托链(其实与我们在学链表时的实现方式是一致的)。
当委托链表被调用时,它首先会调用委托中在其前面的委托对象,这里如果被调的回调方法具有返回值,将被丢失,委托链只会返回最后一次调用回调方法的返回值。
委托示例
这是一个我自认为比较经典的委托示例(给排序算法传递一个动态比较的函数)。
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
namespaceMyDelegateTest
{
///<summary>
///说明:给排序算法传递一个动态比较函数的委托示例
///作者:文野
///联系:stwyhm.cnblogs.com
///</summary>
//进行排序的委托
publicdelegateboolCompare(intleft,intright);
publicclassDelegateSample
{
privateint[] items;
publicint[] Items
{
set{ items =value; }
get{returnitems; }
}
//比大
publicboolGreater(intleft,intright)
{
returnleft > right;
}
//比小
publicboolLess(intleft,intright)
{
return!Greater(left, right);
}
publicvoidSort(Comparecompare)
{
for(inti = 0; i < items.Length-1; i++)
{
for(intj = i + 1; j < items.Length; j++)
{
if(compare(items[i], items[j]))
{
inttmp = items[i];
items[i] = items[j];
items[j] = tmp;
}
}
}
}
}
}
调用页面
usingSystem;
usingSystem.Data;
usingSystem.Configuration;
usingSystem.Collections;
usingSystem.Web;
usingSystem.Web.Security;
usingSystem.Web.UI;
usingSystem.Web.UI.WebControls;
usingSystem.Web.UI.WebControls.WebParts;
usingSystem.Web.UI.HtmlControls;
usingMyDelegateTest;
publicpartialclassSort: System.Web.UI.Page
{
protectedvoidPage_Load(objectsender,EventArgse)
{
}
protectedvoidButton1_Click(objectsender,EventArgse)
{
DelegateSamplesample =newDelegateSample();
sample.Items = GetItems();
//使用降序
sample.Sort(newCompare(sample.Less));
PrintItems(sample);
}
privatevoidPrintItems(DelegateSamplesample)
{
for(inti = 0; i < sample.Items.Length; i++)
{
Response.Write(sample.Items[i] +"<br/>");
}
}
privateint[] GetItems()
{
string[] str =this.TextBox1.Text.Split(",".ToCharArray());
int[] items =newint[str.Length];
for(inti = 0; i < str.Length; i++)
items[i] =int.Parse(str[i]);
returnitems;
}
protectedvoidButton2_Click(objectsender,EventArgse)
{
DelegateSamplesample =newDelegateSample();
sample.Items = GetItems();
//使用升序
sample.Sort(newCompare(sample.Greater));
PrintItems(sample);
}
}
效果图:
降序
升序
参考资料:
《.NET框架程序设计》
《Visual Basic .Net Power Coding》
分享到:
相关推荐
c#入门学习笔记:含基本数据类型,语法,多线程,正则表达式,委托,XML
c#中的委托与事件把委托事件讲透 读书笔记 学习心得 经典中的经典,彻底弄清楚委托事件,明白他们的本质,并有适合的例子说明
36.GC是什么? 为什么要有GC? 答:GC是垃圾收集器。程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一: System.gc() Runtime.getRuntime().gc() 37.String s = ...
c#学习笔记(1) 51099在线学习网发布 文章来源:网络收集 发布时间:2006-05-25 字体: [大 中 小] 51099在线学习网 http://www.51099.com 1, 结构(struct) 与 类(class) [attributes] [modifiers] struct ...
主要介绍了C#中的委托、事件学习笔记,本文讲解了委托delegate、事件的相关知识并给出代码实例,需要的朋友可以参考下
1、 首先用户发送请求,前端控制器DispatcherServlet收到请求后自己不进行处理,而是委托给其他的解析器进行处理,前端控制器作为统一访问点,进行全局的流程控制; 2、 DispatcherServlet把请求转交给...
我们有多种方式获取对象的改变,如[委托、通知](https://github.com/pro648/tips/wiki/委托、通知传值的...这个demo主要以字符串、数组为例来学习键值编码和键值观察。 详细介绍查看下面文章: 源码地址:
md类型的文档,里面有代码块可以直接复制,实现窗体拖动阴影等常见问题,和窗口委托传值的实现方式,注释清晰,亲测可用
项目施工委托管理协议书(20210819160454).pdf
C#学习 01_类.htm.txt 02_构造函数的执行序列.htm.txt 03_抽象类和接口.htm.txt 04_结构类型.htm.txt 05_类成员的定义.htm.txt 06_类成员的其他议题.htm.txt 07_接口的执行.htm.txt 08_集合.htm.txt 09_...
在实践中,委托是创建线程安全类最有效的策略之一:用已有的线程安全类来管理所 有状态即可。
委托是创建线程安全类的最有效策略,只需要让现有的线程安全类管理所有的状态 在现有线程安全类中添加功能 将同步策略文档化 基础构建模块 同步容器类 分类 Vector Hashtable 实现...
本文实例讲述了Symfony2学习笔记之模板用法。分享给大家供大家参考,具体如下: 我们知道,controller负责处理每一个进入Symfony2应用程序的请求。实际上,controller把大部分的繁重工作都委托给了其它地方,以使...
最近在学习kotlin,发现了一些比较重要的知识点,所以下面这篇文章主要给大家介绍了关于Kotlin开发笔记之委托属性与区间的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
C#学习 01_类.htm.txt 02_构造函数的执行序列.htm.txt 03_抽象类和接口.htm.txt 04_结构类型.htm.txt 05_类成员的定义.htm.txt 06_类成员的其他议题.htm.txt 07_接口的执行.htm.txt 08_集合.htm.txt 09_...
36. 二进制文件读写 37. 文本文件读写 38. 存储容器 39. 遍历容器 40. 隐式数据共享 41. model/view 架构 42. QListWidget、QTreeWidget 和 QTableWidget 43. QStringListModel 44. QFileSystemModel 45. 模型 46. ...
这个文档包含了HTML/css的一些基础,还有JavaScript中的基础语法、DOM、BOM还有一些学习js中面向对象、和移动web开发、AJAX、jQuery的一些总结,还有些Web前端与移动开发面试宝典; 6、什么是事件冒泡/捕获? 事件...
SpringMVC1,回顾MVC1.1,什么是MVC MVC是模型(Model),视图(View),控制器(Controller)的简写,是一种软件设计规范。是将数据,显示,业务逻辑分离的... Controller(控制器) :接收用户请求,委托给模型进行