C#中的委托解析

时间:2022-03-24 03:22:51

标签:   委托   

谈及到C#的基本特性,“委托”是不得不去了解和深入分析的一个特性。对于大多数刚入门的程序员谈到“委托”时,都会想到“将方法作为方法的参数进行传递”,很多时候都只是知道简单的定义,主要是因为“委托”在理解上有较其他特性比较难的地方。在本次说明中,不会将委托的简单声明和调用作为重点。

“委托”不需要直接定义一个要执行的行为,而是将这个行为用某种方法“包含”在一个对象中。这个对象可以像其他任何对象那样使用。在该对象中,可以执行封装的操作。可以选择将委托看作之定义了一个方法的接口,将委托的实例看作实现了那个接口的对象。

在“委托”的相关定义中,我们可以不难看出,“委托与方法“相比较于“接口与类”有着设计理念上的相似部分,产生的背景源于”设计原则“中的”开放-封闭原则“,”开放-封闭“原则:是说软件实体(类,模块,函数等等)应该可以扩展,但是不可修改。换一种说法可能更好的理解”对于扩展是开放的,对于更改是封闭的“,面对新的需求,对于程序的改动是通过增加新的代码进行的,而不是更改现有的代码。

在C#中委托用delegate关键字定义,使用new操作符构造委托实例,采用传统的方法调用语法来回调函数(只是要用引用了委托对象的一个变量代替方法名)。在C#中,委托在编译的时候会被编译成类。对于委托的一个说明:委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。委托类既可嵌套在一个类型中定义,也可以在全局范围内定义。由于委托是类,凡是可以定义类的地方,都可以定义委托。

接下来我们来看一下”委托“的组成,需要满足的条件:

1.声明委托类型。

2.必须有一个方法包含了要执行的代码。

3.必须创建一个委托实例。

4.必须调用委托实例。

接下来大致的了解一下上面所提出的4项条件:

委托类型实际上只是参数类型的一个列表以及返回类型。规定了类型的实例能表示的操作。在调用一个委托实例的时候,必须保证使用的参数完全匹配,而且能以指定的方式使用返回值。对于委托实例的创建,取决于操作使用实例方法还是静态方法(如果操作是静态方法,指定类型名称就可以,如果是操作实例方法,需要先创建类型的实例)。对于委托的调用,可以直接调用委托的实例的方法就可以完成对应的操作。

以上谈及了”委托“的定义和组成,接下来我们来了解一下如何将方法绑定到”委托“上,以及委托的合并和删除。

可以将多个方法赋给同一个委托,委托实例实际有一个操作列表与之关联。在System.Delegate类型中提供了两个静态方法Combine()和Remove()负责委托实例的新增和删除操作。但是在我们的实际开发中,较多的采用-=和+=操作符。

在FCL中,所有的委托类型都派生自MulticastDelegate,该类型在System.MulticastDelegate类型中。

具体来看一下Combine()方法的底层实现代码:

[System.Runtime.InteropServices.ComVisible(true)]          public static Delegate Combine(params Delegate[] delegates)          {             if (delegates == null || delegates.Length == 0)                  return null;             Delegate d = delegates[0];             for (int i = 1; i < delegates.Length; i++)                  d = Combine(d,delegates[i]);               return d;          }public static Delegate Combine(Delegate a, Delegate b)          {             if ((Object)a == null)                  return b;             return  a.CombineImpl(b);         }

 以上两个方法为System.Delegate类型中,CombineImpl方法在MulticastDelegate重写。

[System.Security.SecuritySafeCritical]           protected override sealed Delegate CombineImpl(Delegate follow)         {              if ((Object)follow == null)                  return this;             if (!InternalEqualTypes(this, follow))                 throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTypeMis"));               MulticastDelegate dFollow = (MulticastDelegate)follow;             Object[] resultList;              int followCount = 1;              Object[] followList = dFollow._invocationList as Object[];             if (followList != null)                  followCount = (int)dFollow._invocationCount;             int resultCount;             Object[] invocationList = _invocationList as Object[];              if (invocationList == null)             {                  resultCount = 1 + followCount;                  resultList = new Object[resultCount];                 resultList[0] = this;                  if (followList == null)                 {                     resultList[1] = dFollow;                 }                  else                 {                      for (int i = 0; i < followCount; i++)                          resultList[1 + i] = followList[i];                 }                  return NewMulticastDelegate(resultList, resultCount);             }             else             {                  int invocationCount = (int)_invocationCount;                 resultCount = invocationCount + followCount;                  resultList = null;                  if (resultCount <= invocationList.Length)                 {                      resultList = invocationList;                     if (followList == null)                     {                         if (!TrySetSlot(resultList, invocationCount, dFollow))                              resultList = null;                     }                      else                      {                         for (int i = 0; i < followCount; i++)                          {                             if (!TrySetSlot(resultList, invocationCount + i, followList[i]))                             {                                 resultList = null;                                  break;                             }                          }                      }                 }                  if (resultList == null)                 {                     int allocCount = invocationList.Length;                      while (allocCount < resultCount)                         allocCount *= 2;                        resultList = new Object[allocCount];                       for (int i = 0; i < invocationCount; i++)                         resultList[i] = invocationList[i];                     if (followList == null)                      {                         resultList[invocationCount] = dFollow;                      }                      else                     {                          for (int i = 0; i < followCount; i++)                             resultList[invocationCount + i] = followList[i];                     }                 }                  return NewMulticastDelegate(resultList, resultCount, true);             }          }