C#中的事件(委托的發布和訂閱、事件的發布和訂閱、EventHandler類、Windows事件)

目錄

一、委托的發布和訂閱

1.訂閱操作符號“+="和取消訂閱操作符號“-=”

2.示例源碼

二、事件的發布和訂閱

三、EventHandler類

四、Windows事件


????????C#中的事件是指某個類的對象在運行過程中遇到的一些特定事情,而這些特定的事情有必要通知給這個對象的使用者。當發生與某個對象相關的事件時,類會使用事件將這一對象通知給用戶,這種通知即稱為“引發事件”。引發事件的對象稱為事件的源或發送者。

一、委托的發布和訂閱

????????由于委托能夠引用方法,而且能夠鏈接和刪除其他委托對象,因而就能夠通過委托來實現事件的“發布和訂閱”。

  通過委托來實現事件處理的過程,通常需要以下4個步驟:
? 定義委托類型,并在發布者類中定義一個該類型的公有成員。
? 在訂閱者類中定義委托處理方法。
? 訂閱者對象將其事件處理方法鏈接到發布者對象的委托成員(一個委托類型的引用)上。
? 發布者對象在特定的情況下“激發”委托操作,從而自動調用訂閱者對象的委托處理方法。

1.訂閱操作符號“+="和取消訂閱操作符號“-=”

?????????“+=”在這里不是邏輯運算符,而是用于指定響應事件時要調用的方法。這類方法稱為事件處理程序,叫 注冊/訂閱事件,用在操作類名后。

//訂閱符號+=
public static void SubscribeToRing(SchoolRing schoolRing)  
{schoolRing.OnBellSound += SchoolJow;
}

????????與之相反功能的“-=”就是取消訂閱、退訂操作符。

//取消訂閱操作符“-=”
public static void CancelSubscribe(SchoolRing schoolRing) ?
{schoolRing.OnBellSound -= SchoolJow;
}

2.示例源碼

// 委托的發布和訂閱事件namespace Demo
{class Program{static void Main(string[] args){SchoolRing sr = new();                          //創建學校鈴聲類的對象Students.SubscribeToRing(sr);                   //訂閱鈴聲Console.Write("請輸入打鈴參數(1:表示打上課鈴;2:表示打下課鈴):");sr.Jow(Convert.ToInt32(Console.ReadLine()));    //打鈴動作Console.ReadLine();}}public delegate void RingEvent(int ringKind);           //聲明一個委托類型/// <summary>/// 定義鈴聲類SchoolRing/// 類中發布一個委托,定義函數Jow/// </summary>public class SchoolRing{public RingEvent? OnBellSound;            //委托發布,就好像定義一個實例對象public void Jow(int ringKind)             //定義一個公有成員Jow(),打鈴{if (ringKind == 1 || ringKind == 2){Console.Write(ringKind == 1 ? "上課鈴聲響了," : "下課鈴聲響了,");if (OnBellSound != null)         //不等于空,說明它已經訂閱了具體的方法(即它已經引用了具體的方法){OnBellSound!(ringKind);      //回調OnBellSound委托所訂閱(或引用)的具體方法}}else{Console.WriteLine("這個鈴聲參數不正確!");}}}/// <summary>/// 定義學生類Students/// 類中定義三個函數/// </summary>public class Students{public static void SubscribeToRing(SchoolRing schoolRing)  //學生們訂閱鈴聲這個委托事件{schoolRing.OnBellSound += SchoolJow;}public static void SchoolJow(int ringKind){if (ringKind == 2)             //打了下課鈴{Console.WriteLine("同學們開始課間休息!");}else if (ringKind == 1)        //打了上課鈴{Console.WriteLine("同學們開始認真學習!");}}public static void CancelSubscribe(SchoolRing schoolRing)  //取消訂閱鈴聲動作{schoolRing.OnBellSound -= SchoolJow;}}
}

二、事件的發布和訂閱

????????事件是一種特殊的類型,發布者在發布一個事件之后,訂閱者對它只能進行自身的訂閱或取消,而不能干涉其他訂閱者。
事件是類的一種特殊成員:即使是公有事件,除了其所屬類型之外,其他類型只能對其進行訂閱或取消,別的任何操作都是不允許的,因此事件具有特殊的封裝性。和一般委托成員不同,某個類型的事件只能由自身觸發。

????????使用事件的目的是:解決安全隱患和不能干涉其他訂閱者。事件的使用方法:C#提供了專門的事件處理機制,以保證事件訂閱的可靠性,其做法是在發布委托的定義中加上event關鍵字,其他代碼不變。

//事件的使用方法
public event RingEvent OnBellSound;    //事件發布
//不安全的事件訂閱,當不使用event關鍵字時,系統會會忽視威脅的存在
//當使用event關鍵字修飾時,系統會報錯
schoolRing.OnBellSound = SchoolJow;   //系統會報錯的,應使用+=
schoolRing.OnBellSound = null;        //系統會報錯的,禁止指向null
schoolRing.OnBellSound2 = SchoolJow;  //系統會報錯的,事件只能由自身觸發

三、EventHandler類

????????在事件發布和訂閱的過程中,定義事件的類型(即委托類型)是一件重復性的工作,為此,.NET類庫中定義了一個EventHandler委托類型,并建議盡量使用該類型作為事件的委托類型。該委托類型的定義為:

public delegate void EventHandler(object sender,EventArgs e);

????????其中,

????????object類型的參數sender表示引發事件的對象,由于事件成員只能由類型本身(即事件的發布者)觸發,因此在觸發時傳遞給該參數的值通常為this。例如,可將SchoolRing類的OnBellSound事件定義為EventHandler委托類型,那么觸發該事件的代碼就是“OnBellSound(this,null);”

????????EventHandler委托的第二個參數e表示事件中包含的數據。如果發布者還要向訂閱者傳遞額外的事件數據,那么就需要定義EventArgs類型的派生類。

// EventHandler類
namespace _09_1
{class Program{/// <summary>/// 操作流程:創建發布者實例→訂閱該實例→發布者開始發布/// </summary>static void Main(string[] args){SchoolRing sr = new();                                     //創建學校鈴聲類的對象Students.SubscribeToRing(sr);                          //訂閱鈴聲Console.Write("請輸入打鈴參數(1:表示打上課鈴;2:表示打下課鈴):");sr.Jow(Convert.ToInt32(Console.ReadLine()));    //發布者觸發打鈴動作,事件只能由發布者觸發Console.ReadLine();}}public delegate void RingEvent(int ringKind);           //聲明一個委托類型/// <summary>/// 發布者/// 校鈴種類及對應的處理方法/// 定義鈴聲類SchoolRing,類中發布一個委托,定義函數Jow方法/// </summary>public class SchoolRing{public event EventHandler? OnBellSound;   //委托發布,就好像定義一個實例對象public void Jow(int ringKind)                      //定義一個公有成員Jow(),打鈴方法{if (ringKind == 1 || ringKind == 2){Console.Write(ringKind == 1 ? "上課鈴聲響了," : "下課鈴聲響了,");if (OnBellSound != null)                    //不等于空,說明它已經訂閱了具體的方法(即它已經引用了具體的方法){                                                     //為了安全,事件成員只能由類型本身觸發(this),OnBellSound!(this, new Students.RingEventArgs(ringKind));}}else{Console.WriteLine("這個鈴聲參數不正確!");}}}/// <summary>/// 訂閱者/// 定義學生類Students/// 類中定義三個函數:訂閱、訂閱方法、取消訂閱/// </summary>public class Students{/// <summary>/// 訂閱/// </summary>public static void SubscribeToRing(SchoolRing schoolRing)  //學生們訂閱鈴聲這個委托事件{schoolRing.OnBellSound += SchoolJow;}/// <summary>/// EventHandler委托的第二個參數e表示事件中包含的數據。/// </summary>/// <param name="sender">/// 事件的訂閱者可以通過sender參數來了解是哪個對象觸發的事件(這里當然是事件的發布者),/// 不過在訪問對象時通常要進行強制類型轉換/// </param>/// <param name="e"></param>public static void SchoolJow(object? sender, EventArgs e){if (((RingEventArgs)e).RingKind == 2)             //下課鈴,e強制轉化內RingEventArgs類型{Console.WriteLine("同學們開始課間休息!");}else if (((RingEventArgs)e).RingKind == 1)     //上課鈴,e強制轉化內RingEventArgs類型{Console.WriteLine("同學們開始認真學習!");}}/// <summary>/// 取消訂閱/// </summary>/// <param name="schoolRing"></param>public static void CancelSubscribe(SchoolRing schoolRing){schoolRing.OnBellSound -= SchoolJow;}/// <summary>/// EventArgs類型的派生類/// 如果發布者還要向訂閱者傳遞額外的事件數據,那么就需要定義EventArgs類型的派生類。/// 例如,由于需要把打鈴參數(1或2)傳入事件中,則可以定義如下的RingEventArgs類:/// </summary>/// <param name="ringKind">/// 鈴聲參數/// </param>public class RingEventArgs(int ringKind) : EventArgs{//描述鈴聲種類的字段private readonly int ringKind = ringKind;//獲取打鈴參數public int RingKind         {get { return ringKind; }}}}
}

四、Windows事件

????????事件在Windows這樣的圖形界面程序中有著極其廣泛的應用,事件響應是程序與用戶交互的基礎。用戶的絕大多數操作,都可以觸發相關的控件事件。關于此類事件,詳見作者發布的有關Windows窗體應用的文章,此處省略十萬字。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165797.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165797.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165797.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【海德教育】河北初級職稱報名條件:

河北助理工程師 學歷要求 大專畢業后滿3年&#xff0c;工程類專業 本科畢業后滿1年 &#xff0c;工程類專業 非工程類專業&#xff0c;年限增加2年即可。

多線程,線程池,線程的創建,線程池的參數

文章目錄 多線程-1 高并發〇、使用多線程的場景1. 為什么使用多線程 1. 線程概述1.1 線程和進程1.2 并發和并行1.3 多線程的優勢1.4 程序運行原理1.5 主線程 1.6 線程的 6 種狀態2. 線程的創建和啟動2.1 Thread類2.2創建線程有哪幾種方法2.2.1 繼承**Thread**類&#xff0c;重寫…

centos7 安裝docker

1.卸載舊版本&#xff0c;不管裝沒裝過&#xff0c;執行一下&#xff0c;防止版本沖突 yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine 2. yum安裝gcc相關 以及 安…

electron27-react-mateos:基于electron+react18仿matePad桌面系統

基于Electron27React18ArcoDesign搭建桌面版OS管理系統。 electron-react-mateos 基于最新前端跨端技術棧electron27.xreact18arco-designzustand4sortablejs構建的一款仿制matePad界面多層級路由管理OS系統。 ElectronReactOS支持桌面多路由配置&#xff0c;新開窗口彈窗開啟路…

YB4051系列設備是高度集成的 Li-lon 和 Li-Pol 線性充電器,針對便攜式應用的小容量電池。

YB4051H 300mA 單電池鋰離子電池充電器0.1 mA 終端&#xff0c;45nA 電池漏電流 概述&#xff1a; YB4051系列設備是高度集成的 Li-lon 和 Li-Pol 線性充電器&#xff0c;針對便攜式應用的小容量電池。它是一個完整的恒流/恒壓線性充電器。不需要外部感應電阻&#xff0c;由于…

51單片機利用I/O口高阻狀態實現觸摸控制LED燈

51單片機利用I/O口高阻狀態實現觸摸控制LED燈 1.概述 這篇文章介紹使用I/O口的高阻狀態實現一個觸摸控制LED燈亮滅的實驗。該實驗通過手觸摸P3.7引腳&#xff0c;改變電平信號控制燈的亮滅。 2.實驗過程 2.1.實驗材料 名稱型號數量單片機STC12C20521LED彩燈無1晶振12MHZ1電…

Elasticsearch:ES|QL 函數及操作符

如果你對 ES|QL 還不是很熟悉的話&#xff0c;請閱讀之前的文章 “Elasticsearch&#xff1a;ES|QL 查詢語言簡介???????”。ES|QL 提供了一整套用于處理數據的函數和運算符。 功能分為以下幾類&#xff1a; 目錄 ES|QL 聚合函數 AVG COUNT COUNT_DISTINCT 計數為近…

geemap學習筆記013:為遙感動態GIF圖添加圖名

前言 遙感動態GIF圖可以展示地理區域隨時間的變化&#xff0c;這對于監測自然災害、濕地變化、城市擴展、農田變化等方面非常有用&#xff0c;并且可以反復觀察圖像&#xff0c;以更深入地了解地表的動態變化。本節主要是對遙感動態GIF圖添加圖名&#xff0c;以便于更好地理解…

聚觀早報 |一加12正式開啟預訂;OPPO Reno11系列賣點

【聚觀365】11月24日消息 一加12正式開啟預訂 OPPO Reno11系列賣點 小鵬第三季度營收財報 Claude 2.1 聊天機器人公布 現代汽車將與倫敦大學學院合作 一加12正式開啟預訂 全新的一加12系列公開亮相已有一段時間&#xff0c;不久前一加官方宣布&#xff0c;該機將于12月4日…

android:The application could not be installed: INSTALL_FAILED_TEST_ONLY

1、問題描述 在android12 &#xff08;OPPO PEEM00&#xff09;上安裝APP時&#xff0c;提示上述異常 原因分析&#xff1a; android:testOnly&#xff1a;應用是否是為了測試&#xff0c;它可能向外暴露數據&#xff0c;引發安全漏洞。因此國內廠商的手機檢測到這個屬性為t…

ebpf實戰(一)-------監控udp延遲

問題背景: 為了分析udp數據通信中端到端的延遲,我們需要對整個通信鏈路的每個階段進行監控,找出延遲最長的階段. udp接收端有2個主要路徑 1.數據包到達本機后&#xff0c;由軟中斷處理程序將數據包接收并放入udp socket的接收緩沖區 數據接收流程 2. 應用程序調用recvmsg等a…

<JavaEE> 什么是進程控制塊(PCB Process Control Block)?

目錄 一、進程控制塊的概念 二、進程控制塊的重要屬性 2.1 唯一身份標識&#xff08;PID&#xff09; 2.2 內存指針 2.3 文件描述符表 2.4 狀態 2.5 優先級 2.6 記賬信息 2.7 上下文 一、進程控制塊的概念 進程控制塊&#xff08;Process Control Block, PCB&#xff…

Springboot引入分布式搜索引擎Es RestAPI

文章目錄 RestAPI初始化RestClient創建索引庫刪除索引庫判斷索引庫是否存在總結 RestClient操作文檔增加文檔數據查詢文檔刪除文檔修改文檔批量導入文檔小結 RestAPI ES官方提供了各種不同語言的客戶端&#xff0c;用來操作ES。這些客戶端的本質就是組裝DSL語句&#xff0c;通…

IOS Frida 常用腳本

調用堆棧 console.log("bt:" + Thread.backtrace(this.context,Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join(\n\t)); Hook 調用,修改返回值 // Get a reference to the openURL selectorvar openURL = ObjC.classes.UIApplication["- openURL:&qu…

uni-app 跨端開發注意事項

文章目錄 前言H5正常但App異常的可能性標題二H5正常但小程序異常的可能性小程序正常但App異常的可能性小程序或App正常&#xff0c;但H5異常的可能性App正常&#xff0c;小程序、H5異常的可能性使用 Vue.js 的注意區別于傳統 web 開發的注意H5 開發注意微信小程序開發注意支付寶…

Docker實用篇

Docker實用篇 0.學習目標 1.初識Docker 1.1.什么是Docker 微服務雖然具備各種各樣的優勢&#xff0c;但服務的拆分通用給部署帶來了很大的麻煩。 分布式系統中&#xff0c;依賴的組件非常多&#xff0c;不同組件之間部署時往往會產生一些沖突。在數百上千臺服務中重復部署…

STM32入門筆記15_PWR電源管理模塊

PWR和低功耗模式 PWR簡介 PWR(Power Control) 電源控制PWR負責管理STM32內部的電源供電部分&#xff0c;可以實現可編程電壓檢測器和低功耗模式的功能可編程電壓檢測器(PVD) 可以監控VDD電源電壓&#xff0c;當VDD下降到PVD閾值以下或上升到PVD閾值之上時&#xff0c;PVD會觸…

C++學習之路(一)什么是C++?如何循序漸進的學習C++?【純干貨】

C是一種高級編程語言&#xff0c;是對C語言的擴展和增強。它在C語言的基礎上添加了面向對象編程&#xff08;OOP&#xff09;的特性&#xff0c;使得開發者能夠更加靈活和高效地編寫代碼。 C的名字中的“”符號表示在C語言的基礎上向前發展一步&#xff0c;即“加加”&#x…

iOS APP包分析工具 | 京東云技術團隊

介紹 分享一款用于分析iOSipa包的腳本工具&#xff0c;使用此工具可以自動掃描發現可修復的包體積問題&#xff0c;同時可以生成包體積數據用于查看。這塊工具我們團隊內部已經使用很長一段時間&#xff0c;希望可以幫助到更多的開發同學更加效率的優化包體積問題。 工具下載…

LeeCode前端算法基礎100題(4)- 無重復字符的最長子串

一、問題詳情&#xff1a; 給定一個字符串 s &#xff0c;請你找出其中不含有重復字符的 最長子串 的長度。 示例 1: 輸入: s "abcabcbb" 輸出: 3 解釋: 因為無重復字符的最長子串是 "abc"&#xff0c;所以其長度為 3。示例 2: 輸入: s "bbbbb…