最近在學習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();
}
既然給委託綁定方法用“+=”,那麼不難想到取消對方法的綁定用“-=”。
以上。