1. 程式人生 > >《csharp高階程式設計》 學習筆記 第七章 委託和事件

《csharp高階程式設計》 學習筆記 第七章 委託和事件

第七章 委託和事件
回撥(callback)函式是windows程式設計的一個重要部分。
回撥函式實際上是方法呼叫的指標,也稱為函式指標,是一個非常強大的程式設計特性。
.NET以委託的形式實現了函式指標的概念。
但特殊在於,與c函式指標不同,.NET委託是型別安全的。

7.1 委託
委託是一種特殊的物件型別,其特殊之處在於:
我們以前定義的所有物件都包含資料,而委託包含的是隻是方法的地址。

7.1.1 在csharp中宣告委託
使用委託,需兩個步驟:
1.定義
delegate void IntMethodInvoker(int x);
理解委託的一個要點是它們的型別安全性非常高。
在定義委託時,必須給出它所代表的方法簽名和返回型別等全部細節。

語法上類似方法的定義,但沒有方法體。

***因為定義委託是定義一個新類,故可以在定義類的任何地方定義委託。

注意:
委託實現為派生自基類System. Multicast Delegate的類,System. Multicast Delegate又派生自System.Delegate。

2.建立該委託的例項
注意:
類有兩個不同術語:
類和物件。
但委託只有一個術語。
在建立委託的例項時,所建立的委託的例項仍成為委託。

7.1.2 在csharp中使用委託
private delegate string GetAString();
static void Main()
{
int x = 40;
GetAString firstStringMethod = new GetAString(x.ToString);
Console.WriteLine("String is {0}" + firstStringMethod());
// With firstStringMethod initialized to x.ToString(),
// the above statement is equivalent to saying
// Console.WriteLine("String is {0}" + x.ToString()); }

在csharp中,委託在語法上總是帶有一個引數的建構函式。
這個引數就是委託引用的方法。
*這個方法必須匹配最初定義委託時的返回值,形參。

給委託例項提供括號與呼叫委託類的Invoke()方法完全相同。
firstStringMethod();
firstStringMethod. Invoke();

csharp 2.0 使用委託推斷擴充套件了委託的語法。
GetAString firstStringMethod = new GetAString(x.ToString);
GetAString firstStringMethod = x.ToString;
以上兩行程式碼等價,顯然後者更簡潔。

注意:
給定委託的例項可以表示任何型別的任何物件上的例項方法或靜態方法
--只要方法的簽名匹配。

7.1.5 多播委託(+=和-+操作符)

委託可以包含多個方法。
如果呼叫多播委託,就可以按順序連續呼叫多個方法。
*但只能得到委託呼叫的最後一個方法的結果。
*使用多播委託時,注意對同一委託呼叫方法鏈的順序並未正式定義。

注意:
多播委託是一個派生於System.MulticastDelegate 的類。
System. MulticastDelegate又派生於基類System.Delegate。



7.1.6 匿名方法
到目前為止,要想使委託工作,方法必須已經存在。
但其實還有另一種方式:
即通過匿名方法。
匿名方法是用作委託引數的一個程式碼塊。

定義語法和之前沒有區別。
但在例項化委託時就有區別。
using System;
namespace Wrox.ProCSharp.Delegates
{
class Program
{
delegate string DelegateTest(string val);
static void Main()
{
string mid = ", middle part,";
delegateTest anonDel = delegate(string param)
{
param += mid;
param += " and this was added to the string.";
return param;
};
Console.WriteLine(anonDel("Start of string"));
}
}
}
注意此時在定義anonDel時,不是傳送已知的方法名。
而是使用一個簡單的程式碼塊。

匿名方法的優點是減少了編寫的程式碼。
但是使用匿名方法時,程式碼執行得不太快。
編譯器仍定義了一個方法,該方法只有一個自動指定的名稱。

7.1.7 λ表示式
csharp 3.0 為匿名方法提供新語法:λ表示式。
using System;
namespace Wrox.ProCSharp.Delegates
{
class Program
{
delegate string DelegateTest(string val);
static void Main()
{
string mid = ", middle part,";
DelegateTest anonDel = param = >
{
param += mid;
param += " and this was added to the string.";
return param;
};
Console.WriteLine(anonDel("Start of string"));
}
}
}

7.1.8 協變和抗變
委託呼叫的方法不需要與委託宣告定義的型別相同。
因此可能出現協變和抗變。
1.返回型別協變
方法的返回型別可以是派生於委託定義的型別。
我的理解是“相容”即可。
2.引數型別抗變
委託定義的引數可以不同於委託呼叫的方法。
這裡的“不同”同理1。

7.2 事件(event)
.NET把這些傳送來的訊息封裝在事件中。
如果需要相應某個訊息,就處理對應的事件。

有一定windows程式設計基礎的人對這裡的事件都不會陌生吧。我的理解即是訊息響應。

委託就用作應用程式接受到訊息時封裝事件的方式。

*microsoft設計csharp事件的目的是讓使用者無需理解底層的委託,就可以使用它們。

注意:
這裡的術語“事件”有兩種不同的含義。
第一,表示發生了某件有趣的事。
第二,表示csharp語言中已定義的一個物件,即處理通知過程的物件。

7.2.1 從接收器的角度討論事件
事件接收器是指在發生某些事情時被通知的應用程式、物件或元件。

*而傳送器可以是應用程式中的另一個物件或程式集,在系統事件中,例如滑鼠單擊,傳送器就是.NET執行庫。

public Form1()
{
InitializeComponent();
buttonOne.Click += new EventHandler(Button_Click);
}

注意:
1.返回值總是void。事件處理程式不能有返回值。
2.引數:
只要使用EventHandler委託,引數就應是object和EventArgs。

第一個引數是引發事件的物件。
第二個包含有關時間的有用資訊的物件。
其實對於有一定MFC基礎的人對這些就很熟悉了吧。

在windows使用者介面上,microsoft已經編寫了所有需要的事件傳送器。
他們都在.NET基類中,在windows.form 名稱空間中。


*我的理解是其實這個光看書不好懂,關鍵是自己建幾個專案看看框架的程式碼就一目瞭然了。

7.2.2 生成事件
書上舉了一個例子,此處略。

7.3 小結
.NET開發人員大量使用委託和事件,特別是開發windows forms應用程式。
其實要真正理解委託和事件,就動手去開發個小的windows forms程式是最好的辦法。