C#學習,委托,事件,泛型,匿名方法

目錄

委托

聲明委托

實例化委托

委托的多播

委托的用途

事件

通過事件使用委托

聲明事件

泛型

泛型的特性

泛型方法

泛型的委托

匿名方法

編寫匿名方法的語法


委托

類似于指針,委托是存有對某個方法的引用的一種引用類型變量,引用可以在運行時被改變。特別用于實現事件和回調方法。

聲明委托

委托聲明決定了可由委托引用的方法。委托可以指向一個具有相同標簽的方法。例如,有一個委托:

public delegate int MyDelegate (string s);

上面的委托可以被用于任何一個帶有單一string類型的方法,并且返回一個int類型的值。

語法:

delegate <return type> <delegate-name> <parameter list>

實例化委托

一旦聲明了委托類型,委托對象必須使用 new 關鍵字來創建,且與一個特定的方法有關。當創建委托時,傳遞到 new 語句的參數就像方法調用一樣書寫,但是不帶有參數。例如:

public delegate void printString(string s);
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);

實例:

using System;
?
delegate int NumberChanger(int n);
namespace DelegateAppl
{class TestDelegate{static int num = 10;public static int AddNum(int p){num += p;return num;}
?public static int MultNum(int q){num *= q;return num;}public static int getNum(){return num;}
?static void Main(string[] args){// 創建委托實例NumberChanger nc1 = new NumberChanger(AddNum);NumberChanger nc2 = new NumberChanger(MultNum);// 使用委托對象調用方法nc1(25);Console.WriteLine("Value of Num: {0}", getNum());nc2(5);Console.WriteLine("Value of Num: {0}", getNum());Console.ReadKey();}}
}

結果:

Value of Num: 35
Value of Num: 175

委托的多播

委托的對象可以使用“+”運算符進行合并,可以由一個合并的委托來調用組成它的兩個委托。運算符“-”可以將合并的委托移除出去。

使用委托的這個有用的特點,您可以創建一個委托被調用時要調用的方法的調用列表。這被稱為委托的 多播(multicasting),也叫組播。

using System;
?
delegate int NumberChanger(int n);
namespace DelegateAppl
{class TestDelegate{static int num = 10;public static int AddNum(int p){num += p;return num;}
?public static int MultNum(int q){num *= q;return num;}public static int getNum(){return num;}
?static void Main(string[] args){// 創建委托實例NumberChanger nc;NumberChanger nc1 = new NumberChanger(AddNum);NumberChanger nc2 = new NumberChanger(MultNum);nc = nc1;nc += nc2;// 調用多播nc(5);Console.WriteLine("Value of Num: {0}", getNum());Console.ReadKey();}}
}

結果:

Value of Num: 75

委托的用途

下面的實例演示了委托的用法。委托 printString 可用于引用帶有一個字符串作為輸入的方法,并不返回任何東西。

我們使用這個委托來調用兩個方法,第一個把字符串打印到控制臺,第二個把字符串打印到文件:

using System;
using System.IO;
?
namespace DelegateAppl
{class PrintString{static FileStream fs;static StreamWriter sw;// 委托聲明public delegate void printString(string s);
?// 該方法打印到控制臺public static void WriteToScreen(string str){Console.WriteLine("The String is: {0}", str);}// 該方法打印到文件public static void WriteToFile(string s){fs = new FileStream("e:\\message.txt", FileMode.Append, FileAccess.Write);sw = new StreamWriter(fs);sw.WriteLine(s);sw.Flush();sw.Close();fs.Close();}// 該方法把委托作為參數,并使用它調用方法public static void sendString(printString ps){ps("Hello World");}static void Main(string[] args){printString ps1 = new printString(WriteToScreen);printString ps2 = new printString(WriteToFile);sendString(ps1);sendString(ps2);Console.ReadKey();}}
}

結果:

控制臺:

The String is: Hello World

message.txt文件:

Hello World

事件

事件是在說一個用戶操作,比如按鍵、點擊、鼠標移動等,或者是一些提示信息,比如系統生成的通知,應用程序需要在事件發生時響應事件。使用事件機制實現線程間的通信。

通過事件使用委托

事件在類中聲明且生成,并且通過使用同一個類或者其他類中的委托與事件處理程序關聯。包含事件的類用于發布事,稱為發布器類。其他接受該事件的類被稱為訂閱器類。事件使用發布訂閱模型。發布器是一個包含事件和委托定義的對象。事件和委托之間的聯系也定義在這個對象中。發布器類的對象調用這個事件,并且通知其他對象。

訂閱器是一個介=接受事件并且提供事件處理程序的對象。在發布器類中的委托調用訂閱器類中的方法。

聲明事件

類的內部聲明事件,首先必須聲明該事件的委托類型。例如:

public delegate void BoilerLogHandler(string status);

然后,聲明事件本身,使用 event 關鍵字:

// 基于上面的委托定義事件
public event BoilerLogHandler BoilerEventLog;

上面的代碼定義了一個名為 BoilerLogHandler 的委托和一個名為 BoilerEventLog 的事件,該事件在生成的時候會調用委托。

using System;
namespace SimpleEvent
{using System;/***********發布器類***********/public class EventTest{private int value;
?public delegate void NumManipulationHandler();
?
?public event NumManipulationHandler ChangeNum;protected virtual void OnNumChanged(){if (ChangeNum != null){ChangeNum(); /* 事件被觸發 */}else{Console.WriteLine("event not fire");Console.ReadKey(); /* 回車繼續 */}}
?
?public EventTest(){int n = 5;SetValue(n);}
?
?public void SetValue(int n){if (value != n){value = n;OnNumChanged();}}}
?
?/***********訂閱器類***********/
?public class subscribEvent{public void printf(){Console.WriteLine("event fire");Console.ReadKey(); /* 回車繼續 */}}
?/***********觸發***********/public class MainClass{public static void Main(){EventTest e = new EventTest(); /* 實例化對象,第一次沒有觸發事件 */subscribEvent v = new subscribEvent(); /* 實例化對象 */e.ChangeNum += new EventTest.NumManipulationHandler(v.printf); e.SetValue(7);e.SetValue(11);}}
}

結果:(需要回車進行觸發事件)

event not fire
event fire
event fire

并且可以使用事件來講信息記錄到日志中:

using System;
using System.IO;
?
namespace BoilerEventAppl
{
?// boiler 類class Boiler{private int temp;private int pressure;public Boiler(int t, int p){temp = t;pressure = p;}
?public int getTemp(){return temp;}public int getPressure(){return pressure;}}// 事件發布器class DelegateBoilerEvent{public delegate void BoilerLogHandler(string status);
?// 基于上面的委托定義事件public event BoilerLogHandler BoilerEventLog;
?public void LogProcess(){string remarks = "O. K";Boiler b = new Boiler(100, 12);int t = b.getTemp();int p = b.getPressure();if (t > 150 || t < 80 || p < 12 || p > 15){remarks = "Need Maintenance";}OnBoilerEventLog("Logging Info:\n");OnBoilerEventLog("Temparature " + t + "\nPressure: " + p);OnBoilerEventLog("\nMessage: " + remarks);}
?protected void OnBoilerEventLog(string message){if (BoilerEventLog != null){BoilerEventLog(message);}}}// 該類保留寫入日志文件的條款class BoilerInfoLogger{FileStream fs;StreamWriter sw;public BoilerInfoLogger(string filename){fs = new FileStream(filename, FileMode.Append, FileAccess.Write);sw = new StreamWriter(fs);}public void Logger(string info){sw.WriteLine(info);}public void Close(){sw.Close();fs.Close();}}// 事件訂閱器public class RecordBoilerInfo{static void Logger(string info){Console.WriteLine(info);}//end of Logger
?static void Main(string[] args){BoilerInfoLogger filelog = new BoilerInfoLogger("e:\\boiler.txt");DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent();boilerEvent.BoilerEventLog += newDelegateBoilerEvent.BoilerLogHandler(Logger);boilerEvent.BoilerEventLog += newDelegateBoilerEvent.BoilerLogHandler(filelog.Logger);boilerEvent.LogProcess();Console.ReadLine();filelog.Close();}//end of main
?}//end of RecordBoilerInfo
}

結果,在目標文件中顯示日志為:

Logging Info:
?
Temparature 100
Pressure: 12
?
Message: O. K

泛型

泛型允許編寫一個可以在任何類型下一起工作的類和方法,可以通過數據類型的替代參數編寫類或方法的規范。當編譯器遇到類的構造函數或方法的函數調用時,它會生成代碼來處理指定的數據類型。

using System;
using System.Collections.Generic;
?
namespace GenericApplication
{public class MyGenericArray<T>{private T[] array;public MyGenericArray(int size){array = new T[size + 1];}public T getItem(int index){return array[index];}public void setItem(int index, T value){array[index] = value;}}class Tester{static void Main(string[] args){// 聲明一個整型數組MyGenericArray<int> intArray = new MyGenericArray<int>(5);// 設置值for (int c = 0; c < 5; c++){intArray.setItem(c, c*5);}// 獲取值for (int c = 0; c < 5; c++){Console.Write(intArray.getItem(c) + " ");}Console.WriteLine();// 聲明一個字符數組MyGenericArray<char> charArray = new MyGenericArray<char>(5);// 設置值for (int c = 0; c < 5; c++){charArray.setItem(c, (char)(c+97));}// 獲取值for (int c = 0; c < 5; c++){Console.Write(charArray.getItem(c) + " ");}Console.WriteLine();Console.ReadKey();}}
}

結果:

0 5 10 15 20
a b c d e

泛型的特性

使用泛型是一種增強程序功能的技術,具體表現在以下幾個方面:

  • 它有助于您最大限度地重用代碼、保護類型的安全以及提高性能。

  • 您可以創建泛型集合類。.NET 框架類庫在 System.Collections.Generic 命名空間中包含了一些新的泛型集合類。您可以使用這些泛型集合類來替代 System.Collections 中的集合類。

  • 您可以創建自己的泛型接口、泛型類、泛型方法、泛型事件和泛型委托。

  • 您可以對泛型類進行約束以訪問特定數據類型的方法。

  • 關于泛型數據類型中使用的類型的信息可在運行時通過使用反射獲取。

泛型方法

我們可以通過類型參數聲明泛型方法,例如:

using System;
using System.Collections.Generic;
?
namespace GenericMethodAppl
{class Program{static void Swap<T>(ref T lhs, ref T rhs){T temp;temp = lhs;lhs = rhs;rhs = temp;}static void Main(string[] args){int a, b;char c, d;a = 10;b = 20;c = 'I';d = 'V';
?// 在交換之前顯示值Console.WriteLine("Int values before calling swap:");Console.WriteLine("a = {0}, b = {1}", a, b);Console.WriteLine("Char values before calling swap:");Console.WriteLine("c = {0}, d = {1}", c, d);
?// 調用 swapSwap<int>(ref a, ref b);Swap<char>(ref c, ref d);
?// 在交換之后顯示值Console.WriteLine("Int values after calling swap:");Console.WriteLine("a = {0}, b = {1}", a, b);Console.WriteLine("Char values after calling swap:");Console.WriteLine("c = {0}, d = {1}", c, d);Console.ReadKey();}}
}

結果:

Int values before calling swap:
a = 10, b = 20
Char values before calling swap:
c = I, d = V
Int values after calling swap:
a = 20, b = 10
Char values after calling swap:
c = V, d = I

將a,b,c,d進行交換,a,b,c,d的類型并不相同。

泛型的委托

可以通過類型參數來定義泛型委托:

using System;
using System.Collections.Generic;
?
delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl
{class TestDelegate{static int num = 10;public static int AddNum(int p){num += p;return num;}
?public static int MultNum(int q){num *= q;return num;}public static int getNum(){return num;}
?static void Main(string[] args){// 創建委托實例NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);NumberChanger<int> nc2 = new NumberChanger<int>(MultNum);// 使用委托對象調用方法nc1(25);Console.WriteLine("Value of Num: {0}", getNum());nc2(5);Console.WriteLine("Value of Num: {0}", getNum());Console.ReadKey();}}
}

結果:

Value of Num: 35
Value of Num: 175

匿名方法

委托是用于引用與其具有相同標簽的方法。換句話說,可以使用委托對象調用可由委托引用的方法。匿名方法 提供了一種傳遞代碼塊作為委托參數的技術。匿名方法是沒有名稱只有主體的方法。在匿名方法中您不需要指定返回類型,它是從方法主體內的 return 語句推斷的。

編寫匿名方法的語法

匿名方法是通過使用 delegate 關鍵字創建委托實例來聲明的。例如:

delegate void NumberChanger(int n);
NumberChanger nc = delegate(int x)
{Console.WriteLine("Anonymous Method: {0}", x);
};

代碼塊 Console.WriteLine("Anonymous Method: {0}", x); 是匿名方法的主體。

委托可以通過匿名方法調用,也可以通過命名方法調用,即,通過向委托對象傳遞方法參數。

其中,匿名方法的主體之后要加一個“;”

例如:

using System;
?
delegate void NumberChanger(int n);
namespace DelegateAppl
{class TestDelegate{static int num = 10;public static void AddNum(int p){num += p;Console.WriteLine("Named Method: {0}", num);}
?public static void MultNum(int q){num *= q;Console.WriteLine("Named Method: {0}", num);}
?static void Main(string[] args){// 使用匿名方法創建委托實例NumberChanger nc = delegate (int x){Console.WriteLine("Anonymous Method: {0}", x);};
?nc(10);
?nc = new NumberChanger(AddNum);
?nc(5);
?nc = new NumberChanger(MultNum);
?nc(2);Console.ReadKey();}}
}

結果:

Anonymous Method: 10
Named Method: 15
Named Method: 30

由于匿名方法沒有方法簽名,只有方法體,所以無法使用命名方法類似的 方法名(); 去調用,所以只能將由委托變量去調用它,換言之,匿名方法將自己唯一擁有的方法主體交給委托,讓委托代理執行。

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

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

相關文章

vue中使用faker庫生成指定類型的隨機數據

介紹 Faker.js 是十分流行的 Node.js 工具庫&#xff0c;2022年初&#xff0c;Faker.js的作者突然刪庫跑路&#xff0c;導致眾多應用程序崩潰&#xff0c;為了繼續使用Faker的功能&#xff0c;社區的幾位開發者組成團隊決定創建并維護新項目faker-js/faker&#xff0c;現其已成…

Docker+Selenium Grid搭建自動化測試平臺

安裝docker yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager –add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum install docker-ce -y Create a Docker Network docker network create grid 下載鏡像 hu…

laravel-admin之 解決上傳圖片不顯示 $form->image(‘image‘); 及 $grid->column(‘image‘);

參考 https://blog.csdn.net/u013164285/article/details/106017464 $grid->column(‘image’)->image(‘http://wuyan.cn’, 100, 100); // //設置服務器和寬高 圖片上傳的域名 上傳的圖片不顯示 在 這里設置了圖片的上傳路徑 在這里設置 域名 就可以回顯圖片

【計算機視覺|生成對抗】帶條件的對抗網絡進行圖像到圖像的轉換(pix2pix)

本系列博文為深度學習/計算機視覺論文筆記&#xff0c;轉載請注明出處 標題&#xff1a;Image-to-Image Translation with Conditional Adversarial Networks 鏈接&#xff1a;Image-to-Image Translation with Conditional Adversarial Networks | IEEE Conference Publicati…

如何學習正則表達式

正則是什么&#xff0c;能做什么&#xff1f; 正則&#xff0c;就是正則表達式&#xff0c;英文是 Regular Expression&#xff0c;簡稱 RE。顧名思義&#xff0c;正則其實就是一種描述文本內容組成規律的表示方式。 在編程語言中&#xff0c;正則常常用來簡化文本處理的邏輯…

Android DataStore:安全存儲和輕松管理數據

關于作者&#xff1a;CSDN內容合伙人、技術專家&#xff0c; 從零開始做日活千萬級APP。 專注于分享各領域原創系列文章 &#xff0c;擅長java后端、移動開發、人工智能等&#xff0c;希望大家多多支持。 目錄 一、導讀二、概覽三、使用3.1 Preferences DataStore添加依賴數據讀…

LVS負載均衡集群-NAT模式部署

集群 集群&#xff1a;將多臺主機作為一個整體&#xff0c;然后對外提供相同的服務 集群使用場景&#xff1a;高并發的場景 集群的分類 1.負載均衡器集群 減少響應延遲&#xff0c;提高并發處理的能力 2&#xff0c;高可用集群 增強系統的穩定性可靠性&…

封裝vue2局部組件都要注意什么

一. 關于局部組件組成的三個部分&#xff08;template, script, style&#xff09; template > 組件的模板結構 &#xff08;必選&#xff09; 每個組件對應的模板結構&#xff0c;需要定義到template節點中 <template><!-- 當前組件的dom結構&#xff0c;需…

Java SPI加載機制

SPI加載機制 SPI&#xff08;Service Provider Interface&#xff09;是一種通過外界配置來加載具體代碼內容的技術手段。SPI是JDK內置的一種服務提供發現機制&#xff0c;用于實現框架的擴展和組件替換。 在SPI中&#xff0c;框架提供一整套接口&#xff0c;使用者實現這些接…

React源碼解析18(8)------ 實現單節點的Diff算法

摘要 經過之前的幾篇文章&#xff0c;我們已經實現了一個可以進行更新渲染的假React。但是如果我們把我們的jsx修改成這樣&#xff1a; function App() {const [age, setAge] useState(20)const click function() {setAge(age 1)}return age % 2 0 ? jsx("div"…

學習紅外成像儀開發注意要點

學習紅外成像儀開發注意要點 三河凡科科技飛訊紅外成像儀開發學習注意要點 紅外成像儀是一種高級的光學設備&#xff0c;可用于探測、分析和顯示紅外輻射&#xff0c;它廣泛應用于醫學、軍事、石油、礦產資源勘探等領域。紅外成像儀的開發需要注意以下幾個方面&#xff1a; 1…

(搜索) 劍指 Offer 12. 矩陣中的路徑 ——【Leetcode每日一題】

?劍指 Offer 12. 矩陣中的路徑 難度&#xff1a;中等 給定一個 m * n 二維字符網格 board 和一個字符串單詞 word 。如果 word 存在于網格中&#xff0c;返回 true &#xff1b;否則&#xff0c;返回 false 。 單詞必須按照字母順序&#xff0c;通過相鄰的單元格內的字母構…

使用Rust編寫的一款使用遺傳算法、神經網絡、WASM技術的模擬生物進化的程序

模擬生物進化程序 Github地址&#xff1a;FishLife 期待各位的star??? 本項目是一個模擬生物進化的程序&#xff0c;利用遺傳算法、神經網絡技術對魚的眼睛和大腦進行模擬。該項目是使用 Rust 語言編寫的&#xff0c;并編譯為 WebAssembly (Wasm) 格式&#xff0c;使其可以…

QT學習方法

1 .類的學習方法 第一步:從UI文件中,找到界面的類—QMainWindow第二步:在Qt Creator工具中,找到“幫助”按鈕,進入到幫助菜單界面,在選擇"索引",在Look for:輸入類名,找到類名,雙擊條目中的類名,在右側會顯示出來類的詳細內容第三步:在右側,可根據內容目錄…

Spring項目使用Redis限制用戶登錄失敗的次數以及暫時鎖定用戶登錄權限

文章目錄 背景環境代碼實現0. 項目結構圖&#xff08;供參考&#xff09;1. 數據庫中的表&#xff08;供參考&#xff09;2. 依賴&#xff08;pom.xml&#xff09;3. 配置文件&#xff08;application.yml&#xff09;4. 配置文件&#xff08;application-dev.yml&#xff09;5…

Camera Link 接口

Camera Link是一個標準的接口協議&#xff0c;用于高速的圖像數據傳輸&#xff0c;常被用在工業相機和圖像處理系統之間。這個標準由自動視覺協會&#xff08;Automated Imaging Association&#xff0c;簡稱AIA&#xff09;在2000年發布&#xff0c;旨在實現各種廠家之間的高性…

在ubuntu+cpolar+rabbitMQ環境下,實現mq服務端遠程訪問

文章目錄 前言1.安裝erlang 語言2.安裝rabbitMQ3. 內網穿透3.1 安裝cpolar內網穿透(支持一鍵自動安裝腳本)3.2 創建HTTP隧道 4. 公網遠程連接5.固定公網TCP地址5.1 保留一個固定的公網TCP端口地址5.2 配置固定公網TCP端口地址 前言 RabbitMQ是一個在 AMQP(高級消息隊列協議)基…

使用opencv4.7.0部署yolov5

yolov5原理和部署原理就不說了&#xff0c;想了解的可以看看這篇部署原理文章 #include <fstream> #include <sstream> #include <iostream> #include <opencv2/dnn.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp>/…

【Java轉Go】快速上手學習筆記(二)之基礎篇一

目錄 創建項目數據類型變量常量類型轉換計數器鍵盤交互流程控制代碼運算符 創建項目 上篇我們安裝好了Go環境&#xff0c;和用IDEA安裝Go插件來開發Go項目&#xff1a;【Java轉Go】快速上手學習筆記&#xff08;一&#xff09;之環境安裝篇 。 這篇我們開始正式學習Go語言。我…

MyBatis動態SQL:打造靈活可變的數據庫操作

目錄 if標簽trim標簽where標簽set標簽foreach標簽 動態SQL就是根據不同的條件或需求動態地生成查詢語句&#xff0c;比如動態搜索條件、動態表或列名、動態排序等。 if標簽 在我們填寫一些信息時&#xff0c;有些信息是必填字段&#xff0c;有的則是非必填的&#xff0c;這些…