.NET漫游指南-002-委托

什么是委托?为什么要用委托?委托有那几种形式?怎么使用委托?

委托的定义:

委托是一种特殊类型的对象(也就是说,可以看作是一个特殊的类),包含一个或者多个方法的地址。

为什么要用委托:

当需要把一个方法进行传递时就需要用到委托来实现,在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();
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值