C#阶段提高之---委托(delegate)

 

委托是什么?

      委托是一种定义方法签名的类型,可以与具有兼容签名的任何方法关联。 您可以通过委托调用方法。委托用于将方法作为参数传递给其他方法。事件处理程序就是通过委托调用的方法。您可以创建一个自定义方法,当发生特定事件时某个类(例如 Windows 控件)就可以调用您的方法。通俗地讲委托如其名字,就是我要办的事情交给一个方法来办理,这个方法可以作为参数传递其他方法。

 

     委托类型派生自 .NET Framework 中的 Delegate 类。 委托类型是 (sealed)密封的,不能从 Delegate 中派生委托类型,也不可能从中派生自定义类。 由于实例化委托是一个对象,所以可以将其作为参数进行传递,也可以将其赋值给属性。这样,方法便可以将一个委托作为参数来接受,并且以后可以调用该委托。这称为异步回调,是在较长的进程完成后用来通知调用方的常用方法。以这种方式使用委托时,使用委托的代码无需了解有关所用方法的实现方面的任何信息。此功能类似于接口所提供的封装。

以下是通过Reflector 7.0 反编译出来的微软.NET框架集中封装好的部分Delegate类的部分代码:

   1:  [Serializable, ClassInterface(ClassInterfaceType.AutoDual), ComVisible(true)]
   2:  public abstract class Delegate : ICloneable, ISerializable
   3:  {
   4:      // Fields
   5:      internal object _methodBase;
   6:      [ForceTokenStabilization]
   7:      internal IntPtr _methodPtr;
   8:      [ForceTokenStabilization]
   9:      internal IntPtr _methodPtrAux;
  10:      [ForceTokenStabilization]
  11:      internal object _target;
 

反编译的代码仅供参考,不过大致可以看出这些定义的细节,获得delegate的设计里理念,明白为什么delegate是密封的,抽象的!

 

使用委托:

   委托的定义与方法的定义相似,加上关键字delegate声明这是一个委托类型。同样可以存在自己的参数,形式如下:

 

   1:  public delegate void MyDelegates(string message);
 

 

     委托是一种安全地封装方法的类型,它与 C 和 C++ 中的函数指针类似。 与 C 中的函数指针不同,委托是面向对象的、类型安全的和保险的。上面的这个例子是封装一个字符串作为参数返回类型为空的委托。

     下面我通过一个排序的算法演示委托的使用方式,在这个演示的方法中我我提出进一步的请求完善这个排序。

     首先我的详细需求是,通过委托对一个数组进行排序,这个数组可以接受任何的对象(object),第一步先实现接受Int的排序,后续会实现string,以及类对象的排序等等,至于这个排序的方式完全有我们自己定义。

    先来声明一个委托,将来要接受一个方法作为参数,就是先来为我们自己设计的排序方式(方法)占个位置,后来我们自己的定义方法出来后有委托来实现。代码:

   1:  namespace SortDelegeter
   2:  {
   3:      public delegate int SortAnyDelegeter(object obj1,object obj2);
   4:  }

 

下面继续通过一个类实现排序的基本思路功能:这个类文件名字叫做SortAnything.cs 核心代码:

   1:    public class SortAnything
   2:      {
   3:          //这里是对将要排序的对象的处理
   4:          public SortAnyDelegeter sortAnyDelegeter;
   5:          public void SortAny(object[] obj,SortAnyDelegeter sortDelegate)
   6:          {
   7:              for (int i = 0; i < obj.Length-1; i++)
   8:              {
   9:                  for (int j = 0; j < obj.Length - 1 - i; j++)
  10:                  {
  11:                      if (sortDelegate(obj[j + 1], obj[j]) < 0)
  12:                      {
  13:                          object temp = obj[j];
  14:                          obj[j]=obj[j+1];
  15:                          obj[j + 1] = temp;
  16:   //地方有限,节约缩进的距离  
  17:   }} }  }  }

在这个类中我们首先将委托初始化,设置委托类型的变量sortAnyDelegeter,然后在排序方法中使用委托,这个排序方法传递两个参数一个是排序的对象,另一个是使用的委托对象。在11行的代码中我们开始使用委托,传入委托的两个参数。这里请注意委托的返回类型是Int,因此这里我们可以直接比较大于小于0.基本算法的内部还是基本的冒泡排序。

我们的主方法的调用中可以实现这样的代码:

 

   1:   class Program
   2:      {
   3:          static void Main(string[] args)
   4:          {
   5:              //排序的算法使用委托完成(任意数据。字符的排序)
   6:              SortAnything sort = new SortAnything();
   7:              //int[] number = new int[] { 32, 2, 34, 2, 13, 32, 12 };
   8:              //这种定义方式有错误,
   9:              //因为int[]的数组不允许隐式转换为object[]数组
  10:              object[] number = { 32,2,34,2,13,32,12};
  11:              sort.SortAny(number, SortNumber);
  12:              //输出数组
  13:              for (int i = 0; i < number.Length; i++)
  14:              {
  15:                  Console.WriteLine(number[i].ToString());
  16:              }
  17:   
  18:          }
  19:   
  20:          //排序数字类型的委托,实现方法
  21:          public static int SortNumber( object a,object b)
  22:          {
  23:              return (int)a - (int)b;
  24:          }
  25:      }

       21-25行的代码具体定义比较的方法,这个方法既是当年我们处心积虑使用委托占用的位置。委托当年的占位就是为了这位同学啊!当地委托是怎么实现功能的呢?我们来看11行的代码,通过类对象加点来访问冒泡排序的方法,参数是两个即(排序对象,委托的服务对象,也就是那个被委托的方法),这既是委托,可以经现有的方法直接传给委托的实例,也就是说委托占的位置让这个方法(SortNumber)坐上了。在这里被委托的方法就是SortNumber(object a,object b)。这样就可以实现排序了。

      到此为止,已经使用了委托的方式。然而先来来了一个字符串数组也要排序,总不能也是用这个方法排序吧,要是这样,排序结果肯定使你头疼。我们可以重新写一个方法对这个字符串数字排序,只需定义排序规则而已。

   1:       public static int SortString(object a, object b)
   2:          {
   3:              //这里不写自己的方法了,借用预定义,从简!只为了说明委托
   4:              return String.Compare((string)a, (string)b);
   5:          }

 

 

在使用的时间,顶替上面10,11行的代码改写为:

   1:      //object[] number = { 32,2,34,2,13,32,12};
   2:              object[] number = { "I ","Love","You","Do","You","Know" };
   3:              sort.SortAny(number, SortString);
   4:              //输出数组
   5:              for (int i = 0; i < number.Length; i++)
   6:              {
   7:                  Console.WriteLine(number[i].ToString());
   8:              }

不仅仅如此,我们还可以无限扩展,当然这种扩展没有牵涉到设计模式,设计的有良性,只是为了演示简单的委托使用。

 

什么时间使用委托:

     委托的基本性质就是这样的,那么什么时间使用委托呢?

  1. –多线程
  2. –自定义类(控件、通信类……(事件))
  3. –窗体之间回传值
  4. –正则表达式中替换Email掩码Replace()
  5. –…

这些只是委托的部分知识,深入研究委托,事件,委托的多播等等只是会更好加深委托的使用。

posted @ 2012-05-11 22:33  这里显示的是昵称  阅读(992)  评论(0编辑  收藏  举报
新浪微博