.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();        }    }}
原创粉丝点击