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.mzph.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;这些…