您的位置:首页 > 编程语言 > C#

【C#语言基础】--委托(Delegate)(一)

2011-03-29 17:58 507 查看
[b]一.动机[/b]

  在Winform程序中我们经常有这样一种需求,就是在一个主窗口中,当用户点击添加按钮时弹出一个子窗口,用户输入数据,最后点击保存或者关闭窗口后需要主窗口中列表能够刷新,以显示出刚刚添加的数据,或者一些传递参数,改变某个控件的值等等。当然,完全可以使用暴露属性的方式来完成,但是扩展性比较好的做法是利用事件。在子窗体中发布一个事件,在父窗体中订阅这个事件,当子窗体保存数据后触发这个事件以修改父窗体中的某个控件的值,代码如下:
  1:定义委托与委托参数

View Code

/// <summary>
/// 比较2个数的大小的委托
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
public delegate bool CompareHandler(int first, int second);

class Program
{

static void Main(string[] args)
{
int[] items = { 1, 2, 26, 32, 13, 5, 6, 9, 12 };
Console.WriteLine("按数字大小排序:");
BubbleSort(items, GraterThan);
foreach (int item in items)
{
Console.WriteLine(item);
}
Console.WriteLine("按字符方式排序:");
BubbleSort(items, AlphabeticalGraterThan);
foreach (int item in items)
{
Console.WriteLine(item);
}
Console.Read();
}
public static void BubbleSort(int[] items, CompareHandler handler)
{
for (int i = items.Length - 1; i >= 0; i--)
{
for (int j = 1; j <= i; j++)
{

if (handler(items[j - 1], items[j]))
{
int tmp = items[j - 1];
items[j - 1] = items[j];
items[j] = tmp;
}

}
}
}
/// <summary>
/// 按数字大小排序
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
public static bool GraterThan(int first, int second)
{
return first > second;
}
/// <summary>
/// 按字符方式排序
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
public static bool AlphabeticalGraterThan(int first, int second)
{
return first.ToString().CompareTo(second.ToString()) > 0;
}

}


  代码很简单,声明了一个比较2个数字大小的委托,他通过不同的回调函数来实现了不同的比较行为。结果运行如下

  


  我们打开IL反汇编程序看看在CLR中,委托到底是什么摸样

  


  从IL中看出程序中的CompareHandler被编译成了一个类,并且继承了System.MulticastDelegate这个类(MulticastDelegate派生自Delegate),里面包含了4个方法
  第一个为构造器 CompareHandler(Object object, IntPtr method)
  第二个 virtual Invoke(int value)
  第三个 virtual BeginInvoke(int value,AsyncCallback callback,Object obj)
  第四个virtual EndInvoke(IasyncResult result)
  这里重点看一下构造函数和Invoke方法,后面2个主要是涉及到异步委托的问题,将会在后面讨论到。
  在内部:
  因为派生自MulticastDelegate,他其中包含了几个重要的非公有字段。
  _target: 委托对象中为非静态方法时保存回调方法的对象,静态方法则为null
  _methodPtr: 回调方法的标识
  _invocationList:如果为委托链是存储委托数组
  如下图



  构造函数主要有一个类型为object的参数和一个IntPtr型的methoInfo,从名字可以看出,第一个参数object接收的是委托的回调函数所在那个对象中,例子中如果GraterThan 不是静态的,就是Program的对象,如果是静态的,则为null。第二个参数则是回调函数的引用。构造函数还会做一些其他的处理和初始化,根据委托的类型给invocationList赋值等等。
  在外部:
  我们知道的Target和Method属性,这2个属性的内部字段这里不用说大家也能猜到,需要说明的是,这个时候Method的类型是MethodInfo,这个也是在内部做了些许转换吧。有了这2个属性,我们又可以做一些检查,比如你可以限制这个委托调用的回调函数必须是某个类的对象的函数,还可以检查回调函数的名称(虽然可能意义不是很大)
  Invoke函数:
在上面的代码中,在我们使用handler(items[j - 1], items[j]) 的时候,编译在内部调用了Invoke方法,这里是查看IL可以得出的结论,在Invoke方法内部,他取得_target和_methodPtr的值,然后调用被构造函数包装好了的某个对象上的回调函数。

  


  最后,Invoke方法的签名跟我们的委托的签名是一致的。所以,上面的代码可以被替换为if(handler!=null)
handler.Invoke(items[j - 1], items[j]); 这里的是否为null的判断是必须的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: