国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

使用 .NET 對事件進行編程

2019-11-18 12:01:48
字體:
來源:轉載
供稿:網友

  您可能已經對事件進行編程若干年了,但是遷移到 .NET Framework 仍然需要您重新檢查事件的內部工作,因為 .NET Framework 中的事件位于委托的頂層。 對委托的了解越多,對事件進行編程時所具有的駕馭能力越強。 開始使用公共語言運行庫 (CLR) 的某個事件驅動框架(例如 Windows? Forms 或 asp.net)時,理解事件在較低的級別如何工作至關重要。 本月我的目標是使您理解事件在較低的級別如何工作。
  
  什么是事件?
  事件是一種形式化的軟件模式,在該模式中,通知源將對一個或多個處理程序方法進行回調。 因此,事件類似于接口和委托,因為它們提供了設計使用回調方法的應用程序的方法。 但是,事件極大地提高了工作效率,因為它們使用起來比接口或委托更輕易。 事件答應編譯器和 Visual Studio? .NET IDE 在幕后為您做大量的工作。
  
  涉及事件的設計基于事件源和一個或多個事件處理程序。 事件源可以是一個類也可以是一個對象。 事件處理程序是綁定到處理程序方法的委托對象。 圖 1 顯示了綁定到其處理程序方法的事件源的高級別視圖。
  
 使用 .NET 對事件進行編程(圖一)

  
圖 1 事件源和處理程序

  
  每個事件都是根據特定的委托類型定義的。 對于事件源定義的每個事件,有一個基于事件的基礎委托類型的私有字段。 該字段用于跟蹤多路廣播委托對象。 事件源還提供答應您注冊所需數量的事件處理程序的公用注冊方法。
  
  當您創建事件處理程序(委托對象)并在事件源中注冊它時,事件源只是將新的事件處理程序追加到列表的結尾。 然后,事件源可以使用私有字段在多路廣播委托上調用 Invoke,該多路廣播委托將依次執行所有注冊的事件處理程序。
  
  事件的真正的妙處在于對其進行設置的大量工作都已經為您做好了。 正如您很快就會看到的,無論任何時候您定義事件時,Visual Basic? .NET 編譯器都會通過自動添加私有委托字段和公用注冊方法幫助您工作。 您還將看到 Visual Studio .NET 可以通過代碼生成器提供更多的幫助,代碼生成器可以自動發出適用于您的處理程序方法的主干定義。
  
  對事件進行編程
  由于 .NET 中的事件建立在委托的頂層,因此它們的基礎的管道具體信息與較低版本的 Visual Basic 中所一直使用的截然不同。 但是,Visual Basic .NET 的語言設計者們在保持事件編程的語法與較低版本的 Visual Basic 一致方面做得很好。 在很多情況下,對事件進行編程涉及的語法與您習慣使用的熟悉的老語法相同。 例如,您將使用 Event、RaiseEvent 和 WithEvents 等要害字,而它們的行為方式與其在較低版本的 Visual Basic 中的行為方式幾乎完全相同。
  
  讓我們通過創建一個基于事件的簡單的回調設計開始。 首先,我需要通過使用 Event 要害字在類定義內定義一個事件。 必須根據特定的委托類型定義每個事件。 下面是定義自定義委托類型和用來定義事件的類的一個示例:
  
  Delegate Sub LargeWithdrawHandler(ByVal Amount As Decimal)
  
  Class BankAccount
   Public Event LargeWithdraw As LargeWithdrawHandler
   '*** other members omitted
  End Class
  
  在本示例中,LargeWithdraw 事件被定義為實例成員。 在本設計中,BankAccount 對象將充當事件源。 假如希望類而不是對象充當事件源,應該使用 Shared 要害字將事件定義為共享成員。
  
  對事件進行編程時,知道編譯器在幕后為您做了大量額外的工作這一點很重要。 例如,當您將我剛才向給您看過的 BankAccount 類的定義編譯到程序集時,您認為編譯器會做什么? 圖 2 顯示了在中間語言反匯編程序 ILDasm.exe 中檢查生成的類定義時,該定義是什么樣的。 該視圖毫無保留地向您顯示了 Visual Basic .NET 編譯器在幕后做了多少工作來幫助您。
  
使用 .NET 對事件進行編程(圖二)

  
圖 2 ILDasm 中的類定義

  
  當您定義事件時,編譯器在類定義內生成四個成員。 第一個成員是基于委托類型的私有字段。 該字段用于跟蹤對委托對象的引用。 編譯器通過采用事件本身的名稱并添加后綴“Event”生成該私有字段的名稱。 這意味著創建名為 LargeWithdraw 的事件將導致創建名為 LargeWithdrawEvent 的私有字段。
  
  編譯器還生成兩個方法,幫助注冊和注銷將成為事件處理程序的委托對象。 這兩個方法使用標準的命名規則進行命名。 用于注冊事件處理程序的方法使用事件的名稱,并帶有前綴“add_”。 用于注銷事件處理程序的方法使用事件的名稱,并帶有前綴“remove_”。 因此,為 LargeWithdraw 事件創建的兩個方法名為 add_LargeWithdraw 和 remove_LargeWithdraw。
  
  Visual Basic .NET 編譯器通過調用 Delegate 類的 Combine 方法為將委托對象作為參數接受并將其添加到處理程序列表中的 add_LargeWithdraw 生成一個實現。 編譯器通過在 Delegate 類中調用 Remove 方法為從列表中刪除一個處理程序方法的 remove_LargeWithdraw 生成一個實現。
  
  第四個也是最后一個添加到類定義中的成員是表示事件本身的成員。 在圖 2 中,您應該能夠找到名為 LargeWithdraw 的事件成員。 它是旁邊帶有一個倒三角的成員。 但是,您應該注重到,該事件并不象其它三個成員一樣真的是一個物理成員。 相反,它是一個僅包含元數據的成員。
  
  此僅包含元數據的事件成員很有價值,因為它可以向該類支持的編譯器和其他開發工具通知 .NET Framework 中事件注冊的標準模式。 該事件成員還包含注冊方法和注銷方法的名稱。 這使得 Visual Basic .NET 和 C# 等托管語言的編譯器可以在編譯時查找注冊方法的名稱。
  
  Visual Studio .NET 是查找此僅包含元數據的事件成員的開發工具的另一個很好的示例。 當 Visual Studio .NET 發現類定義包含事件時,它將自動生成處理程序方法的主干定義以及將它們作為事件處理程序進行注冊的代碼。
  
  在開始討論激發事件之前,我想提出一個有關用于定義事件的委托類型的限制。 用于定義事件的委托類型不能有返回值。 您必須使用 Sub 要害字而不是 Function 要害字定義委托類型,如下所示:
  
  '*** can be used for events
  Delegate Sub BaggageHandler()
  Delegate Sub MailHandler(ItemID As Integer)
  
  '*** cannot be used for events
  Delegate Function QuoteOfTheDayHandler(Funny As Boolean) As String
  
  對此限制有很充分的原因。 當涉及與若干處理程序方法綁定的多路廣播委托時,處理返回值相當困難。 在多路廣播委托上調用 Invoke 返回與調用列表中的最后一個處理程序方法相同的值。 但是,捕捉較早在列表中出現的處理程序方法的返回值并不那么簡單。 不需要捕捉多個返回值只會使事件更輕易使用。
  
  激發事件
  現在,讓我們修改 BankAccount 類使其在提款數量超出 $5000 閾值時能夠激發一個事件。 激發 LargeWithdraw 事件的最簡單的方法是在一個方法、屬性或構造函數的實現中使用 RaiseEvent 要害字。 您可能會覺得該語法很熟悉,因為它類似于您在較低版本的 Visual Basic 中使用的語法。 下面是從 Withdraw 方法激發 LargeWithdraw 事件的一個示例:
  
  Class BankAccount
   Public Event LargeWithdraw As LargeWithdrawHandler
   Sub Withdraw(ByVal Amount As Decimal)
  '*** send notifications if required
  If (Amount > 5000) Then
   RaiseEvent LargeWithdraw(Amount)
  End If
  '*** perform withdrawal
   End Sub
  End Class
  
  雖然語法與較低版本的 Visual Basic 相同,但是激發事件時所發生的事情則與現在截然不同。 使用 RaiseEvent 要害字激發事件時,Visual Basic .NET 編譯器生成執行每個事件處理程序所需的代碼。 例如,當您編譯以下代碼時您認為會出現什么情況?
  
  RaiseEvent LargeWithdraw(Amount)
  
  Visual Basic .NET 編譯器將此表達式擴展為在保留多路廣播委托對象的私有字段上調用 Invoke 的代碼。 換句話說,使用 RaiseEvent 要害字與在以下 snippet 中編寫代碼具有完全相同的效果:
  
  If (Not LargeWithdrawEvent Is Nothing) Then
   LargeWithdrawEvent.Invoke(Amount)
  End If
  
  注重,Visual Basic .NET 編譯器生成的代碼執行檢查以確保 LargeWithdrawEvent 字段包含對某個對象的有效引用。 這是因為 LargeWithdrawEvent 字段的值在第一個處理程序方法注冊之前一直為 Nothing。 因此,除非當前至少有一個處理程序方法已注冊,否則生成的代碼并不嘗試調用 Invoke。
  
  您應該能夠對激發事件進行觀察。 使用 RaiseEvent 要害字或者根據編譯器自動生成的 LargeWithdrawEvent 私有字段直接進行編程通常并沒有什么分別。 兩種方法都生成相同的代碼:
  
  '*** this code
  RaiseEvent LargeWithdraw(Amount)
  
  '*** is the same as this code
  If (Not LargeWithdrawEvent Is Nothing) Then
   LargeWithdrawEvent.Invoke(Amount)
  End If
  
  在很多情況下,您可能喜歡使用 RaiseEvent 要害字語法,因為它需要的鍵入較少,生成的代碼較簡潔。 但是,在某些情況下,當您需要較多控制時,根據 LargeWithdrawEvent 私有字段進行明確編程可能會有意義。 讓我們看一個這種情況的示例。
  
  想象以下情況:BankAccount 對象有三個事件處理程

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 京山县| 孝感市| 邛崃市| 灌云县| 义马市| 隆德县| 平罗县| 婺源县| 米林县| 林州市| 安陆市| 万载县| 武平县| 连南| 喀什市| 始兴县| 常熟市| 楚雄市| 高安市| 德格县| 朝阳县| 大悟县| 大竹县| 财经| 武邑县| 鄱阳县| 海林市| 万载县| 巍山| 抚州市| 乌鲁木齐市| 平利县| 罗甸县| 石城县| 泰州市| 江油市| 竹北市| 尚志市| 伽师县| 江口县| 长兴县|