委托是尋址方法的.NET版本,使用委托可以將方法作為參數(shù)進(jìn)行傳遞。委托是一種特殊類型的對(duì)象,其特殊之處在于委托中包含的只是一個(gè)活多個(gè)方法的地址,而不是數(shù)據(jù)。
委托雖然看起來像是一種類型,但其實(shí)定義一個(gè)委托,是定義了一個(gè)新的類。下面這行代碼,定義了一個(gè)委托,使用ILDasm.exe查看其生成的IL代碼如圖所示:
由圖中紅色框線中可以看出,.NET將委托定義為一個(gè)密封類,派生自基類System.MulticastDelegate,并繼承了基類的三個(gè)方法(稍后討論這三個(gè))。
委托與函數(shù)指針的區(qū)別1、安全性:C/C++的函數(shù)指針只是提取了函數(shù)的地址,并作為一個(gè)參數(shù)傳遞它,沒有類型安全性,可以把任何函數(shù)傳遞給需要函數(shù)指針的地方;而.NET中的委托是類型安全的。
2、與實(shí)例的關(guān)聯(lián)性:在面向?qū)ο缶幊讨校瑤缀鯖]有方法是孤立存在的,而是在調(diào)用方法前通常需要與類實(shí)例相關(guān)聯(lián)。委托可以獲取到類實(shí)例中的信息,從而實(shí)現(xiàn)與實(shí)例的關(guān)聯(lián)。
3、本質(zhì)上函數(shù)指針是一個(gè)指針變量,分配在棧中;委托類型聲明的是一個(gè)類,實(shí)例化為一個(gè)對(duì)象,分配在堆中。
4、委托可以指向不同類中具有相同參數(shù)和簽名的函數(shù),函數(shù)指針則不可以。
class Student
{
private String name = "";
public Student (String _name)
{
this.name = _name ;
}
public Student() {}
public void getStudentName(String _name)
{
if (this.name != "" )
Console.WriteLine("Student's name is {0}", this.name);
else
Console.WriteLine("Student's name is {0}", _name);
}
}
class Teacher
{
private String name;
public Teacher(String _name)
{
this.name = _name;
}
public void getTeacherName(String _name)
{
if (this.name != "")
Console.WriteLine("Teacher's name is {0}", this.name);
else
Console.WriteLine("Teacher's name is {0}", _name);
}
public string getClassName()
{
return "Eanlish";
}
}
}
上述測試代碼運(yùn)行結(jié)果如下:

當(dāng)指向簽名不符的方法時(shí)會(huì)提示如下錯(cuò)誤,證實(shí)了委托的安全性。

下面來看看C#中實(shí)現(xiàn)委托有哪些方式及各自主要適用范圍。
1、常規(guī)實(shí)現(xiàn)

為了簡便輸入,C#支持只傳送地址的名稱給委托的實(shí)例(委托推斷),如下兩行代碼在編譯器看來是一樣的。
實(shí)際上委托的實(shí)例可以引用任何類型的任何對(duì)象上的實(shí)例方法或靜態(tài)方法,只要方法的簽名匹配于委托的簽名即可。所以結(jié)構(gòu)體的方法一樣可以傳遞給委托。
2、多播委托
多播委托具有一個(gè)帶有鏈接的委托列表,稱為調(diào)用列表,在對(duì)委托實(shí)例進(jìn)行調(diào)用的時(shí)候,將按列表中的委托順序進(jìn)行同步調(diào)用。如果委托有返回值,則將列表中最后一個(gè)方法的返回值用作整個(gè)委托調(diào)用的返回值。因此,使用多播委托通常具有void返回類型。
可以使用+=來使委托指向多個(gè)方法的地址,但必須是在委托實(shí)例化之后才可以使用+=來添加新的方法地址(添加重復(fù)的方法地址編譯器不會(huì)報(bào)錯(cuò),但是也不會(huì)重復(fù)執(zhí)行),若想移除其中的方法地址可以使用-=來實(shí)現(xiàn)(需要至少保留一個(gè),即對(duì)于最后一個(gè)方法地址的移除不起作用)。以下代碼中下面兩行無論單獨(dú)保留哪行,最終的執(zhí)行結(jié)果都是相同的。
3、委托數(shù)組
class Program
{
static void Main()
{
Operations[] operations =
{
MathOperations.MultiplyByTwo,
MathOperations.Square
};
for (int i = 0; i < operations.Length; i++)
{
Console.WriteLine("Using operations[{0}]:", i);
DisplayNumber(operations[i], 2.0);
DisplayNumber(operations[i], 7.94);
Console.ReadLine();
}
}
static void DisplayNumber(Operations action, double value)
{
double result = action(value);
Console.WriteLine(
"Input Value is {0}, result of operation is {1}", value, result);
}
}
struct MathOperations
{
public static double MultiplyByTwo(double value)
{
return value * 2;
}
public static double Square(double value)
{
return value * value;
}
}
上述代碼中實(shí)例化了一個(gè)委托數(shù)組operations(與處理類的實(shí)例相同),該數(shù)組的元素初始化為MathOperations類的不同操作,遍歷這個(gè)數(shù)組,可以將每個(gè)操作應(yīng)用到2個(gè)不同的值中。這種用法的好處是,可以在循環(huán)中調(diào)用不同的方法。
新聞熱點(diǎn)
疑難解答
圖片精選