最近在学习C#,今天这篇博客就对C#的重要特性--委托(Delegate)做一下简单介绍。
(一).在介绍委托之前,我们先看以下代码:
private static double Calculate(double param1, double param2)
{
return Calculate_Add(param1, param2);
}
static double Calculate_Add(double param1, double param2)
{
return param1 + param2;
}
Calculate()是一个计算方法,用于计算我们传入的两个double参数,在这个方法中,将再次传递参数调用Calculate_Add()方法,最后返回两个数的和:param1
+ param2。
假设现在Calculate()这个计算方法升级了,可以支持两个数的乘法,那怎么办呢?我们需要再加个乘法版的计算方法:
static double Calculate_Multiply(double param1, double param2)
{
return param1 * param2;
}
这时候,Calculate方法也需要改一改了,不然如何判断到底用哪个版本的计算方法合适呢?在进行这个之前,我们最好再定义一个枚举作为判断的依据:
public enum CalculateType
{
Add, Multiply
}
public double Calculate(double param1, double param2, CalculateType type)
{
switch (type)
{
case CalculateType.Add:
return Calculate_Add(param1, param2);
break;
case CalculateType.Multiply:
return Calculate_Multiply(param1, param2);
break;
}
}
尽管这样暂时实现了需求,但这个解决方案的可扩展性很差,假如日后我们的计算方法又可以支持减法、除法,就不得不翻出修改枚举和Calculate()方法,以适应新的需求。
(二).这里,我们就可以通过C#的委托机制来实现以上需求。
首先,我们需要定义一个委托:
delegate double CalculateDelegate(double param1, double param2);
可以看到,所声明的委托与Calculate_Add()和Calculate_Multiply()方法的声明除了加入delegate关键字以外,其余的完全一样,包括返回值类型和参数。
然后,我们需要修改计算方法Caculate():
rivate static double Calculate(double param1, double param2, CalculateDelegate MakeCalculate)
{
return MakeCalculate( param1, param2);
}
我们注意到,Caculate()方法的参数在原来基础上增加了一个CalculateDelegate委托类型的参数MakeCalculate,这个传入的参数其实就是一个方法,这个方法会在Caculate()方法内部执行。
具体实现代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace ConsoleApplication1
{
//声明委托
delegate double CalculateDelegate(double param1, double param2);
class Program
{
static double Calculate_Add(double param1, double param2)
{
return param1 + param2;
}
static double Calculate_Multiply(double param1, double param2)
{
return param1 * param2;
}
//注意此方法,它接受一个CalculateCalculate类型的参数,该参数是返回值类型为double,参数为两个double类型
private static double Calculate(double param1, double param2, CalculateDelegate MakeCalculate)
{
return MakeCalculate( param1, param2);
}
static void Main(string[] args)
{
double param1 = 2;
double param2 = 3;
double addNum = Calculate(param1, param2, Calculate_Add);
double multiplyNum = Calculate(param1, param2, Calculate_Multiply);
Console.WriteLine(param1 + " + " + param2 + " = " + addNum);
Console.WriteLine(param1 + " * " + param2 + " = " + multiplyNum);
Console.ReadKey();
}
}
}
运行结果如下:
我们在调用Calculate()方法时,接受委托的那个参数传入的是Calculate_Add和Calculate_Multiply两个方法,这两个方法的类型(包括参数和返回值)与委托CalculateDelegate相同,相当于这两个方法是委托实例化出的对象一样。
这样,当计算方法Calculate()想要扩展一个减法或除法运算时,只需增加一个Calculate_Sub或Calculate_Div即可。
(三).好了,这回我们对委托做一个总结:
我们可以这么理解委托,委托是一个类,它定义了某一个方法的类型,这个方法包括了一个返回类型和一个参数列表。它的存在使得可以将该类型的方法当作另一个方法的参数来进行传递(注意只是该类型的方法)。这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
既然委托是一个方法类,那么该委托它实例出来的类对象就是我们作为参数的方法Calculate_Add()、Calculate_Multiply(),所以我们也可以这样修改Main()方法:
static void Main(string[] args)
{
double param1 = 2;
double param2 = 3;
CalculateDelegate delegate1 = Calculate_Add;
CalculateDelegate delegate2 = Calculate_Multiply;
double addNum = Calculate(param1, param2, delegate1);
double multiplyNum = Calculate(param1, param2, delegate2);
Console.WriteLine(param1 + " + " + param2 + " = " + addNum);
Console.WriteLine(param1 + " * " + param2 + " = " + multiplyNum);
Console.ReadKey();
}
输入结果与之前的相同。
我们也可以不把委托作为参数,而是直接通过委托来调用方法,如下:
static void Main(string[] args)
{
double param1 = 2;
double param2 = 3;
CalculateDelegate delegate1 = Calculate_Add;
CalculateDelegate delegate2 = Calculate_Multiply;
double addNum = delegate1(param1, param2);
double multiplyNum = delegate2(param1, param2);
Console.WriteLine(param1 + " + " + param2 + " = " + addNum);
Console.WriteLine(param1 + " * " + param2 + " = " + multiplyNum);
Console.ReadKey();
}
很明显相当于直接调用了Calculate_Add()、Calculate_Multiply()方法。
(四).此外,委托还有一个不同于普通类的特性,可以将多个方法赋给同一个委托,或者叫将多个方法绑定到同一个委托,当调用这个委托的时候,将依次调用其所绑定的方法。看如下例子:
static void Main(string[] args)
{
double param1 = 2;
double param2 = 3;
CalculateDelegate delegate1;
delegate1 = Calculate_Add; // 先给委托类型的变量赋值
delegate1 += Calculate_Multiply; // 给此委托变量再绑定一个方法
// 将依次调用 Calculate_Add 与 Calculate_Multiply 方法
double Num = Calculate(param1, param2, delegate1);
Console.ReadKey();
}
既然给委托绑定方法用“+=”,那么不难想到取消对方法的绑定用“-=”。
以上。