.NET漫游指南-002-委托
来源:互联网 发布:淘宝详情页图片上传 编辑:程序博客网 时间:2024/05/16 23:58
什么是委托?为什么要用委托?委托有那几种形式?怎么使用委托?
委托的定义:
委托是一种特殊类型的对象(也就是说,可以看作是一个特殊的类),包含一个或者多个方法的地址。
为什么要用委托:
当需要把一个方法进行传递时就需要用到委托来实现,在C/C++的时候是提取函数地址的指针进行传递的,但是这样是没有安全性的,因为你无法对其进行安全性校验,这就造成了编码的不可控性,非法的数据就可能被调用。在.NET Framework中就加入了委托的概念,如果要传递方法,就必须把方法的细节封装在一个新型的对象中–委托。所以委托是针对方法进行的操作,委托对数据是什么并不关心(也是面向对象编程思路,只关心自己要处理的)。
委托有几种形式:
1,自定义委托
2,泛型委托:Action,Func,自定义泛型委托
3,匿名委托
4,多播委托
5,Lambda形式的委托
从返回形式来看,委托可以分为两种。一种是有返回值的委托,一种是没有返回值的委托(可以成为事件委托)。这两种形式的委托定义,声明和委托绑定还是有区别的。如下做简要展示。
//定义有返回值的委托pubilc delegate string GenericDelegate<T,S>(T title, S author);//定义无返回值的事件委托public delegate void GenericDelegateEvent<E,P>(E Name, P Address);public class GenericDelegateClass<V,F>{ //声明委托 GenericDelegate<V,F> GDeleValue; //声明事件委托 GenericDelegateEvent<V,F> GDeleEvent = null;}//绑定委托pubilc void Click(object sender , EventArgs e){ GenericDelegateClass<string ,string> gdc = new GenericDelegateClass<string ,string>(); //绑定委托,可以用=。 gdc.GDeleValue = new GenericDelegate<string,string>(Delegate); //绑定事件委托,事件委托只能用+=,-=。 gdc.GDeleEvent += new GenericDelegateEvent<stirng,string>(EventDelegate); public string Delegate<T,S>(T title,S author) { return title.ToString() + author; } private void EventDelegate<V, F>(V name, F address) { // }}
下面举个例子来帮助理解委托的工作方式,这也是面向对象编程的思维方式。
故事里面有三个要素:任务下达,你的组长,你。
今天公司给你们组下达了一个开发任务,你组长接受到任务之后觉得你适合完成这个任务,就将任务委托给了你去实现,你做完之后把结果给你组长。
其实委托的实现流程和上面是一样的(所以叫委托= =)
怎么使用委托
下面用事件来阐述如何使用委托
委托的定义语法如下:
delegate void IntMethodInvoker(int x);
关键词delegate 表示这是个委托对象,void和int参数表示该委托包含的方法带有一个int型的参数且返回值是void。这也体现了委托的安全性。(为什么委托的返回类型要和调用的方法的返回类型一样,一方面是为了保证委托的安全性,另一方面方法的处理结果要靠委托表达出来,所以要一样)
委托的实例化
委托的实例化和普通类的实例化是一样
IntMethodInvoker invoker = new IntMethodInvoker( );
代码下载地址:http://download.csdn.net/download/geshicuowu/9933392
下面举个最简单的例子来展现委托
很明显结果会返回:40
但是上面的这个例子显然没有说到点上,委托的使用看起来和直接使用x.ToString( )方法没有什么特别的优势。(在后面会举一个更能说明委托作用的一个例子。该例子主要是为了表明委托的基本形式,以后的形式都是在此上面的扩展)
泛型委托
其实在实际的项目中,泛型委托的形式更为常见。其中action委托表示引用一个返回void类型的方法,参数范围是0~16个。func委托可以引用具有返回类型的方法。例如func(in T1,out TResult)
下面将举一个泛型委托的例子,也更能体现出委托的特点。(例子来源于c#高级编程)
1:定义一个排序类,里面声明一个static方法,其中一个参数为泛型委托func
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;/// <summary>/// 这个类时用来演示泛型委托的/// 冒泡排序/// </summary>namespace DelegateExample{ class BubbleSort { /// <summary> /// 冒泡排序方法 /// </summary> /// <typeparam name="T">泛型参数</typeparam> /// <param name="sortArry">传入的排序队列</param> /// <param name="comparison">泛型委托</param> /// <returns></returns> static public bool Sort<T>(IList<T> sortArry, Func<T, T, bool> comparison) { for (int j = 0; j < sortArry.Count; j++) { for (int i = j+1; i < sortArry.Count; i++) { if (comparison(sortArry[j], sortArry[i])) { var temp = sortArry[j]; sortArry[j] = sortArry[i]; sortArry[i] = temp; } } } return false; } }}
2:定义一个employee类,其中有工资的比较方法,和上面的泛型委托的参数和返回类型相匹配。
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;/// <summary>/// 自定义的一个员工类/// 用来示范泛型委托的使用/// author:zhangzhen/// date: 2017/08/14/// </summary>namespace DelegateExample{ class Employee { public Employee(string name, double salery) { Name = name; Salery = salery; } public string Name { get; private set; } public double Salery { get; private set; } /// <summary> /// 比较薪资的函数 /// </summary> /// <param name="e1"></param> /// <param name="e2"></param> /// <returns></returns> static public bool compare(Employee e1,Employee e2) { return e1.Salery < e2.Salery; } }}
3:最后时实现类
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;/******************************************* * 这个控制台程序主要用来演示委托delegate的相关知识 * author:zhangzhen * date :2017-08-10 * ******************************************/namespace DelegateExample{ class Program { //定义一个委托 delegate string GetStringInvoker(); static void Main(string[] args) { Employee[] employees = { new Employee("zhangzhen",10000000), new Employee("xiaoming",10000), new Employee("xiaohuang",20000), new Employee("xiaodong",8000) }; BubbleSort.Sort(employees, Employee.compare); foreach(var item in employees) { Console.WriteLine(item.Name + " /// "+ item.Salery); } //让控制台暂停等待输入。 Console.ReadKey(); } }}
输出结果符合预期。
也就是说任何对象(只要该对象中有比较方法,且比较方法的形式符合BubbleSort类中Sort方法中的泛型委托的要求的)都可以使用Sort方法实现冒泡排序。试想,如果没有委托(尤其是泛型委托)的话,这个效果时很难实现的。
多播委托
上面那个排序的例子中,调用一次委托就调用一次方法,如果要调用多个方法,就要多次显示的调用这个委托,使用起来不是很方便,多播委托就比较好的解决了这个问题。
多播委托可以委托多个方法,在调用多播委托时,将按顺序连续调用多个方法。(因为不可能返回多个返回类型,因此多播委托的签名必须是void)多播委托可以使用-=,+=来向委托列表中删减方法或者增加方法。
使用多播委托时的注意点:
1:多播委托并不会严格的按照委托列表中的顺序来执行,也就是说不能把有顺序特定依赖的方法加到委托列表中。
2:多播委托中,如果委托链表中一个方法发生了异常,整个迭代就会终止。为了避免这个问题,Delegate类中定义了GetInvocationList()方法,它返回一个Delegate对象数组,可以利用这个委托调用与委托列表中相关的方法,同时捕获异常,并不会终止迭代。
在一些涉及业务较为繁杂的项目中,泛型委托和多播委托一般都会结合使用。
下面就是一个比较简单的例子(因为多播委托中委托的方法返回类型是void,所以逻辑处理基本都是在被委托的方法中实现)
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;/// <summary>/// 这个类是用来演示多播委托的一个辅助类/// </summary>namespace DelegateExample{ class MultiDelegate { static public void One() { Console.WriteLine("这是方法ONE"); } static public void Two() { Console.WriteLine("这是方法Two"); } }}
下面是实现
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;/******************************************* * 这个控制台程序主要用来演示委托delegate的相关知识 * author:zhangzhen * date :2017-08-10 * ******************************************/namespace DelegateExample{ class Program { /*********************多播委托的演示**********************************/ Action action = MultiDelegate.One; action += MultiDelegate.Two; action += MultiDelegate.One; //将Two方法从委托链表中移除 //action -= MultiDelegate.Two; Delegate[] tempDelegate = action.GetInvocationList(); //下面的形式是不可行的,var没办法调用委托中的方法,必须用Action来修饰item //foreach (var item in tempDelegate) //{ // item(); //} foreach (Action item in tempDelegate) { item(); } //让控制台暂停等待输入。 Console.ReadKey(); } }}
- .NET漫游指南-002-委托
- .NET漫游指南-008-泛型,装箱,泛型委托
- .NET漫游指南-009-泛型事件委托
- .NET漫游指南-003-事件
- .NET漫游指南-005-INotifyProperChanged和List<>,ObservableCollection<>使用
- .NET漫游指南-006-语言集成查询LINQ
- .NET漫游指南-007-WPF中多线程调用界面控件
- Unicode漫游指南
- GitHub 漫游指南
- 【GitHub】GitHub 漫游指南
- .NET漫游指南-011-.NET Framework中处理和引发事件
- .NET漫游指南-004-在dataGrid中添加CheckBox支持单选,多选,全选功能
- .NET漫游指南-010-WPF中的KeyDown和PreviewKeyDown事件的区别和用法
- Cocos2d漫游指南第十一章亦真亦幻
- 转 -- Amazon AWS 漫游指南
- .NET程序员面试指南:解释委托的基本原理
- .NET 委托
- .NET 委托
- 集合
- ST_VL53L0X开发记录_IIC读一个字节的函数的个人理解
- 文件锁以及多路复用方式解决多个用户对一个文件的操作
- mysqlSenior
- ORM数据库DBFlow入门
- .NET漫游指南-002-委托
- hdu6105 Gameia 思维
- 1039. 到底买不买
- javascript中的DOM
- 构造函数的初始化
- 左边定宽,右边自适应宽度布局
- 枚举排列(入门经典7-2)
- Servlet安全性(3)----SSL
- bzoj 2763 [JLOI2011]飞行路线 Dijikstra 分层