微软.NET6开发的C#特性——委托和事件

我是荔园微风,作为一名在IT界整整25年的老兵,看到不少初学者在学习编程语言的过程中如此的痛苦,我决定做点什么,下面我就重点讲讲微软.NET6开发人员需要知道的C#特性,然后比较其他各种语言进行认识。

C#经历了多年发展, 进行了多次重大创新, 大幅优化了开发者的编码体验。在.NET 平台移交给.NET基金会运营后, C#更新的越来越不像原来的C#了,但总体上来说,所有改进依然以优化开发者的编码体验为最终目的。

首先,要记住一张表,如下:

C#版本     发布时间         .NET版本                       VS版本                  CLR版本

C#1.0        2002-2           .NET Framework 1.0     VS.NET 2002      .NET Framework CLR 1.0

C#2.0        2005-11         .NET Framework 2.0     VS2005               .NET Framework CLR 2.0

C#3.0        2006-11         .NET Framework 3.0     VS2008               .NET Framework CLR 2.0 

C#3.0       2007-11          .NET Framework 3.5     VS2008                .NET Framework CLR 2.0 

C#4.0       2010-4           .NET Framework 4.0     VS2010                .NET Framework CLR 4.0

C#5.0       2012-2           .NET Framework 4.5     VS2012               .NET Framework CLR 4.0

C#6.0       2015-7           .NET Framework 4.6      VS2015              .NET Framework CLR 4.0

C#7.0       2016-8           .NET Framework 4.6.2    VS2017(v15)     .NET Framework CLR 4.0

C#7.1       2017-4           .NET Framework 4.7      VS2017(v15.3)   .NET Framework CLR 4.0

C#7.2       2017-10         .NET Framework 4.7.1   VS2017(v15.5)    .NET Framework CLR 4.0

C#7.3       2018-4           .NET Framework 4.7.2   VS2017(v15.8)   .NET Framework CLR 4.0

C#8.0       2019-4           .NET Framework 4.8    VS2019(v16.3)    .NET Framework CLR 4.0

C#8.0       2019-9           .NETCore 3.0                 VS2019(v16.4)    .NETCore CLR 3.0       

C#9.0       2020-11          .NET 5.0                        VS2019(v16.8)    .NET CLR 5.0           

C#10.0     2021-11          .NET 6.0                        VS2022(v17)       .NET CLR 6.0 

看完这张表,我真的是很感慨,从测试版开始,我居然陪伴着.NET和C#走过了二十多年,我不知道有没有微软公司的人在看这篇文章,如果有的话,不知道我这样的二十多年的.NET和C#程序员有没有机会去微软中国和微软亚洲研究院的总部去参观一下,去坐一坐,并作一下技术交流。二十多年了,人生又有几个二十多年啊。

.NET平台是基于IL中间语言的应用运行环境,面向对象语言C#是平台的主要开发语言。除此之外还有同样面向对象的C++/CLI。C++/CLI主要用于和原生C++交互,在.NET平台中仅支持Windows系统。

C#和.NET平台本来是微软为了与Java平台竞争而打造的,C#在设计时充分总结了Java的经验教训,解决了大量Java的基本设计缺陷。本着为一线开发者谋实惠的宗旨,C#设计了大量能减轻开发者的编写负担、容易理解且安全高效的实用功能。为了尽可能降低因安全措施导致性能大幅下降的影响,C#还在有限的情况下保留了C/C++语言的部分语法和功能。到了.NET时代,微软依然在运行时(Runtime)和语言两边同时进行着优化。

随着上世纪九十年代Java的发布,软件公司和开发者开始感受到基于虚拟机的托管语言所带来的好处,微软也不甘示弱,在2001年发布了.NET Framework平台和C#。提供了完整的基础面向对象支持。

委托

委托可以说是C#的一个强大特性。委托这个概念其实是来源于C语言的函数指针,又在面向对象的方面里完成了升级。C语言的函数指针能完成各种非常有效的功能,最典型的就是回调函数,可以说事件驱动的图形界面编程的基石就是函数指针。但是C语言的函数指针可能会导致各种bug,甚至黑客入侵时很多时候也是瞄着函数指针下手。

因为C语言从不验证函数指针所指向的函数。C#开发团队深知函数指针的重要性,必须想办法控制住函数指针,否则后患无穷,因此最终诞生了委托。

委托本身也是一种类型,但是和结构体一样,有专门的定义语法。在方法声明头部的返回类型之前加上访问修饰和delegate关键字就能完成委托类型的定义。委托类型的所有成员都统一由编译器生成。委托是面向对象的函数指针,可以同时保持对方法和目标对象的引用。同时委托又是强类型的,会严格验证所引用的方法签名和委托支持的签名是否兼容。

微软又设计了多播委托,可以让一个委托对象同时引用多个方法,调用委托就能同时调用引用的所有方法,如果多播委托有返回值,只有最后一个委托的返回值有效。实际上所有自定义委托类都隐式派生自多播委托类,继承路径为: System.Object→System.Delegate→System.MulticastDelegate→各种自定义委托

而Java在面对函数指针时选择了删除函数指针。但这个功能本身是非常有必要的,怎么办呢?最后Java选择了用接口去模拟函数指针的功能,并取名叫函数式接口。但是接口不是专门为函数指针设计的,接口的“兼取”导致了函数指针的语义被接口掩盖了。

一个合格的函数式接口只能声明一个方法,但只声明了一个方法的接口却不一定是函数式接口。接口的冗长语法也让实现函数指针的功能变得非常麻烦,这一点稍微对比一下WinForm和安卓的事件处理器的模板代码就能看出来。

虽然后来Java8增加了Lambda表达式和方法引用功能,在一定程度上对代码有所简化,但C#在更早之前就增加了Lambda表达式功能并进行了持续更新。

C#、C和Java的委托定义语法的示例代码如下所示。

(1)C#

namespace Example
{
    public delegate string MyDelegate(string str1, string str2);

  class Program
  {
      public static void Main(string[] args)
      {
          MyDelegate func1;
      }
    }
}

(2) C

//直接声明函数指针变量
char*(*func)(char* str1, char* str2);

//先定义函数指针类型,再声明变量
typedef char* (*MyDelegate)(char* str1, char* str2);
MyDelegate func1;

从对比中可以看出C#的委托定义语法和C还是很像的。

(3)Java

package com. example. coredx. practice;

@FunctionalInterface
public interface MyDelegate{
  String function(String str1, String str2);
}

Java中的 FunctionalInterface注解从 Java 8开始才有,之前的版本中只要接口中只定义一个方法即可,无法单纯从代码上分辨是函数式接口还是普通接口。

事件

事件是和委托配合使用的,为了确保使用事件的代码不会有意无意地调用或破坏委托,C#设计了事件。事件有点类似于属性,能确保只允许外部代码订阅或取消订阅事件,只允许类的内部成员调用触发。没有委托的Java自然无此问题。

C#的事件的示例代码如下:
 

using System;

namespace Example
{
  //定义事件参数
  public class MyEventArgs : EventArgs
   {
    private DateTime striggeredTime;
      private string smessage;

      public DateTime TriggeredTime
      {
        get {return striggeredTime;}
        }

       public string Message
        {
        get {return smessage};
       }
  
       public MyEventArgs(string message)
      {
        smessage= message;
          striggeredTime= DateTime. Now;
        }
    }

  //定义事件处理委托
  public delegate void MyEventHandler(object sender, MyEventArgs args);
  
  class Program
  {
    private static MyEventHandler smyEventHandler;

      //定义事件订阅访问器
    public static event MyEventHandler MyEvent
     {
        add { smyEventHandler += value; }
         remove { smyEventHandler -= value;}
       }

     //用简化语法定义事件订阅访问器
     public static event MyEventHandler MyEvent2;
  
     public static void Main(string[] args)
     {
      if (smyEventHandler != null) smyEventHandler. Invoke (null,new MyEventArgs("程序已启动。");
         if (MyEvent2 != null) MyEvent2.Invoke(null, new MyEventArgs("程序已启动。"));
       }
    }
}

从上面中可以看出C#的event关键字实际上是在类中定义事件处理委托的注册和取消访问器,本质上还是方法,事件本身还是靠委托实现的。也正是因为事件只允许进行注册和取消注册,因此可以避免外部代码有意或无意地调用事件处理委托误触发事件或直接通过赋值破坏事件处理委托。

上面代码中的“object sender, MyEventArgs args”是微软推荐的事件处理模式, WinForm控件的大多数事件都是按照这个模式设计的。其中sender表示引发事件的对象,args表示事件携带的数据。

作者简介:荔园微风,1981年生,高级工程师,浙大工学硕士,软件工程项目主管,做过程序员、软件设计师、系统架构师,早期的Windows程序员,Visual Studio忠实用户,C/C++使用者,是一位在计算机界学习、拼搏、奋斗了25年的老将,经历了UNIX时代、桌面WIN32时代、Web应用时代、云计算时代、手机安卓时代、大数据时代、ICT时代、AI深度学习时代、智能机器时代,我不知道未来还会有什么时代,只记得这一路走来,充满着艰辛与收获,愿同大家一起走下去,充满希望的走下去。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/379387.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络基本知识(二)

文章目录 概要分层为什么分层怎么分层?1.实体2.协议3.服务 分层基本原则正式认识分层详细例子解释 总结 概要 分层知识:概念理解 分层 为什么分层 大致以上五点 为了解决上面的问题(复杂) 大问题划分为小问题 怎么分层&#…

Stable Diffusion 模型下载:Disney Pixar Cartoon Type B(迪士尼皮克斯动画片B类)

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十 下载地址 模型介绍 这是我之前的模型迪士尼皮克斯卡通类型A与我自己训练的Lora在中途旅程图像上的合并结果。与之前的版本相比,男性和老年人看起来更像真正的皮克斯角色&a…

黄金交易策略:手工同向单减保留仓

虽然保留仓的仓位不大,扛个一年半载不是问题,但闲着也可以手工处理掉(10000点以内的不要处理)。挑一个最大的单,同向相同的手数,并把两单的止盈设置中位数(也没有这么严格,差不多就好…

Node.js之npm单独与批量升级依赖包的方式

Node.js之npm单独与批量升级依赖包的方式 文章目录 Node.js之npm单独与批量升级依赖包的方式npm查看与升级依赖包1. 单独安装或升级最新版本2. 查看依赖但不升级1. npm outdated2. npm update 3. 批量升级新版本4. npm-check-updates1. 全局安装2. ncu查看可升级的版本3. 升级依…

【Linux驱动】块设备驱动(三)—— 块设备读写(不使用请求队列)

并非每种块设备都会用到请求队列,从上节可以知道,请求队列的作用是管理和调用IO请求,那么反过来想,如果IO请求较少,那就可以无需使用请求队列。在以下情况中,可以不使用请求队列。 单任务环境: 当系统中只有…

懒人精灵 之 Lua 捕获 json解析异常 ,造成的脚本停止.

Time: 2024年2月8日20:21:17 by:MemoryErHero 1 异常代码 Expected value but found T_END at character 12 异常代码 Expected value but found T_OBJ_END at character 223 处理方案 - 正确 json 示范 while true do--Expected value but found T_END at character 1--Ex…

tab 切换类交互功能实现

tab切换类交互&#xff1a; 记录激活项&#xff08;整个对象/id/index)动态类型控制 下面以一个地址 tab 切换业务功能为例&#xff1a; <div class"text item" :class"{active : activeAddress.id item.id}" click"switchAddress(item)"…

python-pandas查漏补缺

1. create labels for Series 2. 3. 4. 用平均数等去填empty的格子 5. 6. 7.

Pandas 数据处理-排序与排名的深度探索【第69篇—python:文本数据处理】

文章目录 Pandas 数据处理-排序与排名的深度探索1. sort_index方法2. sort_values方法3. rank方法4. 多列排序5. 排名方法的参数详解6. 处理重复值7. 对索引进行排名8. 多级索引排序与排名9. 更高级的排序自定义10. 性能优化技巧10.1 使用nsmallest和nlargest10.2 使用sort_val…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Stepper组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Stepper组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Stepper组件 鸿蒙&#xff08;HarmonyOS&#xff09;仅能包含子组件StepperIte…

【Java EE】----SpringBoot的日志文件

1.SpringBoot使用日志 先得到日志对象通过日志对象提供的方法进行打印 2.打印日志的信息 3.日志级别 作用&#xff1a; 可以筛选出重要的信息不同环境实现不同日志级别的需求 ⽇志的级别分为&#xff1a;&#xff08;1-6级别从低到高&#xff09; trace&#xff1a;微量&#…

L1-088 静静的推荐

一、题目 二、解题思路 如果有的学生天梯赛成绩虽然与前一个人相同&#xff0c;但其参加过 PAT 考试&#xff0c;且成绩达到了该企业的面试分数线&#xff0c;则也可以接受——同一批次这样的人可以有多个&#xff01;&#xff01;&#xff01;如果 pta 分数不低于 175 &#…

【MySQL】:深入理解并掌握DML和DCL

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. DML1.1 添加数据1.2 修改数据1.3 删除数据 二. DCL2.1 管理用户2.2 权限控制…

【已解决】:pip is configured with locations that require TLS/SSL

在使用pip进行软件包安装的时候出现问题&#xff1a; WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available. 解决&#xff1a; mkdir -p ~/.pip vim ~/.pip/pip.conf然后输入内容&#xff1a; [global] ind…

PSM-Net根据Stereo图像生成depth图像

一、新建文件夹 在KITTI数据集下新建depth_0目录 二、激活anaconda环境 conda activate pt14py37三、修改submission.py文件 3.1 KITTI数据集路径 parser.add_argument(--datapath, default/home/njust/KITTI_DataSet/00/, helpselect model)3.2 深度图像输出路径 save…

linux(redhat)重置root密码

首先将root密码改成几乎不可能记住的密码 [rootexample ~]# echo fheowafuflaeijifehowf|passwd --stdin root Changing password for user root. passwd: all authentication tokens updated successfully.重启系统&#xff0c;进入救援模式 出现此页面&#xff0c;按e键 lin…

苏宁易购移动端首页(rem布局)

技术选型 方案∶采取单独制作移动页面方案技术:布局采取rem适配布局( less rem &#xff0b;媒体查询)设计图:设计图采用750px设计尺寸 设置视口标签以及引入初始化样式 <meta name"viewport" content"widthdevice-width, initial-scale1.0, user-scalable…

python-基础篇-列表-脚本

文章目录 01_下标.py02_查找.py03_判断是否存在.py04_体验案例判断是否存在.py05_列表增加数据之append.py06_列表增加数据之extend.py07_列表增加数据之insert.py08_列表删除数据.py09_列表修改数据.py10_列表复制数据.py11_列表的循环遍历之while.py12_列表的循环遍历之for.p…

Redis(02)——事务管理

事务概念 Redis事务的本质是一组命令的集合。事务支持一次执行多个命令&#xff0c;一个事务中所有命令都会被序列化&#xff0c;在事务执行过程中&#xff0c;会按照顺序串行化执行队列中的命令&#xff0c;其他客户端提交的命令请求不会插入到事务执行命令序列中 Redis事务…

【EEG信号处理】对信号进行模拟生成

生成信号的目的还是主要是为了学习和探究后面的分析方法&#xff1b;本文主要是对方法进行整理 瞬态 transient 瞬态信号是指的是一瞬间信号上去了&#xff0c;这种情况我们可以用在时域上高斯模拟 peaktime 1; % seconds width .12; ampl 9; gaus ampl * exp( -(EEG.tim…