当前位置: 首页 > news >正文

C# 事件Event

目录

事件的特点

事件的基本用法

         事件练习

          补充::Action 委托函数


在 C# 中,事件(Event)是一种特殊的委托,基于委托的并为委托提供一个发布/订阅的机制,可以说事件是一个具有特殊签名的委托。

事件的特点

  1. 只能在声明事件的类内部触发(保证封装性)
  2. 订阅者只能通过 += 和 -= 来订阅和取消订阅
  3. 支持多播(多个订阅者可以订阅同一个事件)
  4. 事件是委托的安全包装,防止外部直接调用或赋值

事件的基本用法

event 是在委托上面加上关键字  加上之后在使用委托的时候会增加一些限制 

这里以大学懒人舍友和怨种舍友为例,只有怨种下楼了,才可以给懒人室友带饭、拿快递:

怨种舍友类ToolMan

internal class ToolMan
{public string Name { get; set; }//构造函数public ToolMan(string name){Name = name;}//定义一个委托public delegate void DownDelgate();//event 是在委托上面加上关键字  加上之后在使用委托的时候会增加一些限制 public event DownDelgate downDelgate = null;//创建了一个有参数(string参数类型)的事件  actionpublic event Action<string> action;//调用事件的函数public void Down(){Console.WriteLine($"{Name}下楼了");downDelgate();action("怨种回来了");}//打印字符串显示函数public void Show(string str){Console.WriteLine(str);}
}

懒人舍友类LazyMan

 internal class LazyMan{public string Name { get; set; }public LazyMan(string name) {this.Name = name;}public void TakeFood(){Console.WriteLine($"{Name}买饭");}public void GetFoot(){Console.WriteLine($"{Name}拿快递");}}

主函数调用

先声明一些懒人和调用懒人类中所做的事的函数订阅在事件里:

static void Main(string[] args)
{ToolMan T = new ToolMan("怨种");LazyMan L1 = new LazyMan("小明");LazyMan L2 = new LazyMan("小张");LazyMan L3 = new LazyMan("小李");//+=订阅T.downDelgate += L1.TakeFood;T.downDelgate += L2.TakeFood;T.downDelgate += L3.TakeFood;//-=取消订阅订阅T.downDelgate -= L3.TakeFood;
 Console.WriteLine("怨种出发了");
怨种舍友还没有下楼,委托还不能发生,所以使用事件声明委托这里将不能提前执行会报错//T.downDelgate();//T.action("12300");直接订阅会报错
因此:在ToolMan类中的Down()函数调用写入这两个事件,当下楼函数执行时,事件也会发生。T.Down();}

这里 怨种工具人还没下楼 委托的事件也发生了 这不合理,这样写T.downDelgate(); 直接调用委托 会发现 工具人还没有下楼就执行了操作  事件还没有执行

怎么解决?   使用事件

报错说明: 事件的访问权限与使用场景不匹配

错误本质:C# 中,事件(event)是特殊的委托封装,为保证封装性:

  • 在定义事件的类(ToolMan)外部,事件只能通过 +=(订阅)、-=(取消订阅)操作,不能直接赋值(=)、调用或作为委托变量传递。
  • 代码里的 ToolMan.downDelgate 、ToolMan.action是事件,却在类外部被当作普通委托用了(比如直接调用、赋值等),违反了事件的访问规则,所以编译器报错。

解决方案:这些事件都是怨种下楼之后才能操作的,且这些事件的调用只能在类本身访问使用,所以这里在ToolMan类中的Down()函数调用写入这两个事件,当下楼函数执行时,事件也会发生。

事件练习:

示例代码:

含有事件的类Class1,此处写一个函数Boilwater来判断水温,当水温达到95°,事件发生

internal class Class1
{//创建了一个事件public event Action<int> action;public void Boilwater(){for (int i = 0; i <= 100; i++){if (i>=95){action(i);}}}
}

报警器类Class3

 internal class Class3{public void MakeAi(int paras){Console.WriteLine($"嘀嘀嘀:水已经{paras}");}}

液晶屏类Class2

internal class Class2
{public void ShowMsg(int param){Console.WriteLine($"水温到了 当前水温{param}");}
}

主函数调用

static void Main(string[] args)
{Class1 c1= new Class1();Class2 c2= new Class2();Class3 c3= new Class3();c1.action += c2.ShowMsg;c1.action += c3.MakeAi;c1.Boilwater();
}

 示例代码:

 定义一个类Mom包含 KaiFan事件 和 cook函数

internal class Mom
{public event Action<string> KaiFan;public void cook(){Console.WriteLine("做饭");KaiFan("开饭");}
}

定义一个Dad类 包含虚方法eat

internal class Dad
{public virtual  void eat(string a){Console.WriteLine(a+" 爸爸吃饭");}
}

定义一个Son类继承父类Dad 包含重写eat方法

internal class Son: Dad//继承Dad父类方法
{public override  void eat(string a){Console.WriteLine(a + " 儿子吃饭");}
}

主函数订阅

static void Main(string[] args)
{Mom mom = new Mom();Dad dad = new Dad();Son son = new Son();//订阅mom.KaiFan += Show;mom.KaiFan  += dad.eat;mom.KaiFan += son.eat;//事件发生做饭mom.cook();}
public static void Show(string str)
{Console.WriteLine(str);
}

补充:Action 委托函数

在 C# 中,Action 是一个预定义的泛型委托,位于 System 命名空间下,用于表示没有返回值的方法。它简化了委托的定义,无需手动声明委托类型,直接使用即可。

1. Action 的基本形式

Action 有两种常见形式:

  • 无参数的 Action:表示没有参数且无返回值的方法。

    public delegate void Action();
    
  • 带参数的 Action<T>:泛型版本,支持 1~16 个参数(例如 Action<T1>Action<T1, T2> 等),同样没有返回值。

    // 示例:带两个参数的 Action
    public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
    
http://www.dtcms.com/a/307700.html

相关文章:

  • python中高效构建提示词
  • 软件工程:软件复用
  • 当过滤条件不符合最左前缀时,如何有效利用索引? | OceanBase SQL 优化实践
  • Verilog实现RPC从机(配合AXI_Slave使用)
  • 消息队列学习-----消息消失与积压
  • 操作系统数据格式相关(AI回答)
  • 性能优化(二):JS内存泄漏“探案”:从闭包到事件监听的隐形杀手
  • 经典屏保问题 - 华为OD机试真题(Java 题解)
  • uniapp Vue3版本使用pinia存储持久化插件pinia-plugin-persistedstate对微信小程序的配置
  • Django模型迁移指南:从命令用法到最佳实践
  • 分布式微服务--万字详解 微服务的各种负载均衡全场景以注意点
  • Vue3 + Electron 技术栈下 MAC 地址获取的方法、准确性优化与应对策略
  • mac操作笔记
  • nuxt3: trpc-nuxt和sqlite导致的503错误
  • Python 动态属性和特性(使用动态属性转换数据)
  • 【烧脑算法】Dijkstra 算法:解决最短路问题
  • PHP开发
  • SAP Datasphere 02 - 建模
  • 文件无法复制到u盘,提示0x80071ac3错误
  • SpringBoot原理揭秘--自动装配(终)
  • Cesium 快速入门(二)底图更换
  • Spring Cloud『学习笔记』
  • 前端项目如何同时导入一个库的不同版本
  • SpringMVC的核心架构与请求处理流程
  • React中的this绑定
  • 网关 + MDC 过滤器方案,5分钟集成 日志 traceid
  • Java学习-----SpringBoot的常用注解(下)
  • 嵌入式硬件中瓷片电容的基本原理与详解
  • WebRTC 多媒体 SDP 示例与解析
  • 嵌入式硬件学习(十)—— LED驱动+杂项设备驱动