委托可以这样来理解:它是一种数据类型,和引用类型类似,不过和一般的类相比,委托的实例不是在堆中的数据,而是一个方法。委托类似于引用类型,和C++中的函数指针很相似,但是不同之处就在于,它不是存在于堆中的。正是有了委托我们才得以将函数打包成一个变量进行传递。这就是说,我们不止能够将数据作为参数传递,还可以将一个函数作为参数进行传递,这样就可以在需要的时候方便的进行控制的反转(Ioc,控制反转)。
下面写一个简单的实例进行理解:两个数求其中的较大值、较小值。
/// <summary> /// 两个数求较大值 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> int Max(int x, int y) { return x > y ? x : y; } /// <summary> /// 两个数求较小值 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> int Min(int x, int y) { return x < y ? x : y; } ///创建与上面求较大值和较小值具有相同签名的一个委托 delegate int MyDelegate(int x, int y); MyDelegate md = null;
上面代码先声明了两个函数Max和Min,然后声明具有与上述两函数相同签名的委托 delegate int MyDelegate(int x, int y);
看上述截图输入两个数字,并选择Max或者Min,单击按钮即可获的结果。
private void RbMax_CheckedChanged(object sender, EventArgs e) { if (RbMax.Checked == true) { md = new MyDelegate(Max); } } private void RbMin_CheckedChanged(object sender, EventArgs e) { if (RbMin.Checked == true) { md = new MyDelegate(Min); } }
两个RadioButton按钮的事件可以看出。如果选择了RbMax,则让MyDelegate类型的实例“md”指向Max方法,如果用户选择了求最小值的RbMin,则让MyDelegate类型的实例“md”指向Min方法。这样作的目的,就是要把选择的过程交给用户。
private void BtnReturn_Click(object sender, EventArgs e) { if (this.md == null) { MessageBox.Show("委托md没有指向任何方法!"); return; } int FirstValue = int.Parse(this.TbFirst.Text); int SecondValue = int.Parse(this.TbSecond.Text); MessageBox.Show(md(FirstValue, SecondValue).ToString()); }
输入完两个数字并选择方式之后的单击按钮事件。
从上面的代码中,可以发现,在使用委托之前,先要判断其值是否为空,如果不为空,则可以进行调用,同时,使用者可以看到,在调用md时,我们并没有关心md到底指向了哪一个方法,总之,md不为空的时候,就一定会指向Max和Min当中的一个。
运行效果如下:
实例结束,总结以下几点:
Ø 在C#中,所有的委托都是从System.MulticastDelegate类派生的。
Ø 委托隐含具有sealed属性,即不能用来派生新的类型。
Ø 委托最大的作用就是为类的事件绑定事件处理程序。
Ø 在通过委托调用函数前,必须先检查委托是否为空(null),若非空,才能调用函数。
Ø 在委托实例中可以封装静态的方法也可以封装实例方法。
Ø 在创建委托实例时,需要传递将要映射的方法或其他委托实例以指明委托将要封装的函数原型(.NET中称为方法签名:signature)。注意,如果映射的是静态方法,传递的参数应该是类名.方法名,如果映射的是实例方法,传递的参数应该是实例名.方法名。
Ø 只有当两个委托实例所映射的方法以及该方法所属的对象都相同时,才认为它们是想等的(从函数地址考虑)。