委托是尋址方法的.NET版本,使用委托可以將方法作為參數進行傳遞。委托是一種特殊類型的對象,其特殊之處在于委托中包含的只是一個活多個方法的地址,而不是數據。
委托雖然看起來像是一種類型,但其實定義一個委托,是定義了一個新的類。下面這行代碼,定義了一個委托,使用ILDasm.exe查看其生成的IL代碼如圖所示:
由圖中紅色框線中可以看出,.NET將委托定義為一個密封類,派生自基類System.MulticastDelegate,并繼承了基類的三個方法(稍后討論這三個)。
委托與函數指針的區別1、安全性:C/C++的函數指針只是提取了函數的地址,并作為一個參數傳遞它,沒有類型安全性,可以把任何函數傳遞給需要函數指針的地方;而.NET中的委托是類型安全的。
2、與實例的關聯性:在面向對象編程中,幾乎沒有方法是孤立存在的,而是在調用方法前通常需要與類實例相關聯。委托可以獲取到類實例中的信息,從而實現與實例的關聯。
3、本質上函數指針是一個指針變量,分配在棧中;委托類型聲明的是一個類,實例化為一個對象,分配在堆中。
4、委托可以指向不同類中具有相同參數和簽名的函數,函數指針則不可以。
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";
}
}
}
上述測試代碼運行結果如下:
當指向簽名不符的方法時會提示如下錯誤,證實了委托的安全性。
下面來看看C#中實現委托有哪些方式及各自主要適用范圍。
1、常規實現
為了簡便輸入,C#支持只傳送地址的名稱給委托的實例(委托推斷),如下兩行代碼在編譯器看來是一樣的。
實際上委托的實例可以引用任何類型的任何對象上的實例方法或靜態方法,只要方法的簽名匹配于委托的簽名即可。所以結構體的方法一樣可以傳遞給委托。
2、多播委托
多播委托具有一個帶有鏈接的委托列表,稱為調用列表,在對委托實例進行調用的時候,將按列表中的委托順序進行同步調用。如果委托有返回值,則將列表中最后一個方法的返回值用作整個委托調用的返回值。因此,使用多播委托通常具有void返回類型。
可以使用+=來使委托指向多個方法的地址,但必須是在委托實例化之后才可以使用+=來添加新的方法地址(添加重復的方法地址編譯器不會報錯,但是也不會重復執行),若想移除其中的方法地址可以使用-=來實現(需要至少保留一個,即對于最后一個方法地址的移除不起作用)。以下代碼中下面兩行無論單獨保留哪行,最終的執行結果都是相同的。
3、委托數組
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;
}
}
上述代碼中實例化了一個委托數組operations(與處理類的實例相同),該數組的元素初始化為MathOperations類的不同操作,遍歷這個數組,可以將每個操作應用到2個不同的值中。這種用法的好處是,可以在循環中調用不同的方法。
新聞熱點
疑難解答