欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > C# 事件(Event)

C# 事件(Event)

2025/9/29 13:38:08 来源:https://blog.csdn.net/2401_83367969/article/details/144257374  浏览:    关键词:C# 事件(Event)

文章目录

  • 前言
  • 1、 声明委托
  • 2、 声明事件
  • 3、 触发事件
  • 4、订阅和取消订阅事件
  • 5、示例展示
    • 示例一:基础的事件使用流程
    • 示例二:简单数值变化触发事件
    • 示例三:锅炉系统相关事件应用


前言

  在 C# 中,事件(Event)是一种特殊的成员,它扮演着传递特定事件通知给订阅者的重要角色。事件机制常被用于实现观察者模式,借助这一模式,一个对象能够在自身状态发生变化时,将该变化情况通知给其他相关对象,而且无需了解这些接收通知对象的具体细节信息。
从更宽泛的角度来讲,事件可以是用户进行的各类操作,比如按下按键、点击鼠标、移动鼠标等,也可能是系统生成的提示信息之类的内容。应用程序需要具备在事件发生时做出相应响应的能力,就像应对中断情况那样。此外,在 C# 里还可以利用事件机制来实现线程间的通信功能。
事件相关的几个关键操作
在这里插入图片描述

1、 声明委托

  委托其实就是一个函数签名,在定义事件时,首先得声明该事件将要使用的委托类型。例如:

public delegate void BoilerLogHandler(string status);

  这就定义了一个名为 BoilerLogHandler 的委托,后续的事件会基于这个委托来关联相应的操作逻辑。

2、 声明事件

  使用 event 关键字来声明一个事件,像这样:

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

  如此一来,就声明了一个名为 BoilerEventLog 的事件,当这个事件被触发时,会调用与之关联的委托所指向的方法。

3、 触发事件

  要在合适的时机去调用事件,从而通知所有已订阅该事件的对象。通常会在类中定义一个受保护的虚方法来触发事件,例如:

protected virtual void OnProcessCompleted(EventArgs e)
{ProcessCompleted?.Invoke(this, e);
}

  这里使用 ?.Invoke 语法是为了确保只有在存在订阅者的情况下才去调用事件,避免出现空引用异常等问题。

4、订阅和取消订阅事件

  其他类能够通过 += 和 -= 运算符来分别实现订阅和取消订阅事件的操作。比如:

process.ProcessCompleted += Process_ProcessCompleted;

  这行代码就是订阅者使用 += 运算符订阅事件,并指定了对应的事件处理程序 Process_ProcessCompleted。
发布 - 订阅模型中的角色
发布器(publisher)
  发布器是一个包含事件以及委托定义的对象,并且事件和委托之间的关联也是在这个对象中定义好的。发布器类的对象负责调用事件,进而通知其他相关对象。简单来说,它就是事件的源头,负责向外发送事件通知。
订阅器(subscriber)
  订阅器则是接受事件并提供相应事件处理程序的对象。在发布器类中的委托会去调用订阅器类中定义的方法(也就是事件处理程序),以此来对发生的事件做出具体的处理动作。

5、示例展示

示例一:基础的事件使用流程

以下示例代码展示了在 C# 中较为典型的事件使用方式:

using System;namespace EventDemo
{// 定义一个委托类型,用于事件处理程序public delegate void NotifyEventHandler(object sender, EventArgs e);// 发布者类public class ProcessBusinessLogic{// 声明事件public event NotifyEventHandler ProcessCompleted;// 触发事件的方法protected virtual void OnProcessCompleted(EventArgs e){ProcessCompleted?.Invoke(this, e);}// 模拟业务逻辑过程并触发事件public void StartProcess(){Console.WriteLine("Process Started!");// 这里可以加入实际的业务逻辑// 业务逻辑完成,触发事件OnProcessCompleted(EventArgs.Empty);}}// 订阅者类public class EventSubscriber{public void Subscribe(ProcessBusinessLogic process){process.ProcessCompleted += Process_ProcessCompleted;}private void Process_ProcessCompleted(object sender, EventArgs e){Console.WriteLine("Process Completed!");}}class Program{static void Main(string[] args){ProcessBusinessLogic process = new ProcessBusinessLogic();EventSubscriber subscriber = new EventSubscriber();// 订阅事件subscriber.Subscribe(process);// 启动过程process.StartProcess();Console.ReadLine();}}
}

在这个示例中:
  首先定义了 NotifyEventHandler 委托类型,它规定了事件处理程序的签名,不过在实际中也常常用 EventHandler 或 EventHandler 来替代自定义的委托。
  接着 ProcessBusinessLogic 类作为发布者,声明了 ProcessCompleted 事件,并通过 OnProcessCompleted 方法来触发该事件。
  而 EventSubscriber 类作为订阅者,通过 Subscribe 方法使用 += 运算符订阅事件,并定义了具体的事件处理程序 Process_ProcessCompleted。在 Main 方法中完成订阅操作后启动业务逻辑过程,当业务逻辑完成触发事件时,订阅者的事件处理程序就会被调用执行相应输出。

示例二:简单数值变化触发事件

using System;
namespace SimpleEvent
{// 发布器类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);}}
}

在这个例子里:
  EventTest 类作为发布器,它内部有一个表示数值的变量,并且定义了 NumManipulationHandler 委托以及对应的 ChangeNum 事件,通过 OnNumChanged 方法在数值变化时触发事件。
  subscribEvent 类作为订阅器,定义了 printf 方法作为事件处理程序。在 Main 类的 Main 方法中完成订阅操作后,当调用 SetValue 方法改变数值并满足触发条件时,就会触发事件,进而调用订阅器中的事件处理程序输出相应内容。

示例三:锅炉系统相关事件应用

using System;
using System.IO;namespace BoilerEventAppl
{// Boiler 类class Boiler{public int Temp { get; private set; }public int Pressure { get; private set; }public Boiler(int temp, int pressure){Temp = temp;Pressure = pressure;}}// 事件发布器class DelegateBoilerEvent{public delegate void BoilerLogHandler(string status);// 基于上面的委托定义事件public event BoilerLogHandler BoilerEventLog;public void LogProcess(){string remarks = "O.K.";Boiler boiler = new Boiler(100, 12);int temp = boiler.Temp;int pressure = boiler.Pressure;if (temp > 150 || temp < 80 || pressure < 12 || pressure > 15){remarks = "Need Maintenance";}OnBoilerEventLog($"Logging Info:\nTemperature: {temp}\nPressure: {pressure}\nMessage: {remarks}");}protected void OnBoilerEventLog(string message){BoilerEventLog?.Invoke(message);}}// 该类保留写入日志文件的条款class BoilerInfoLogger : IDisposable{private readonly StreamWriter _streamWriter;public BoilerInfoLogger(string filename){_streamWriter = new StreamWriter(new FileStream(filename, FileMode.Append, FileAccess.Write));}public void Logger(string info){_streamWriter.WriteLine(info);}public void Dispose(){_streamWriter?.Close();}}// 事件订阅器public class RecordBoilerInfo{static void Logger(string info){Console.WriteLine(info);}static void Main(string[] args){using (BoilerInfoLogger fileLogger = new BoilerInfoLogger("e:\\boiler.txt")){DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent();boilerEvent.BoilerEventLog += Logger;boilerEvent.BoilerEventLog += fileLogger.Logger;boilerEvent.LogProcess();}Console.ReadLine();}}
}

在这个与锅炉系统相关的示例中:

  • Boiler 类用于表示锅炉的基本信息,包含温度和压力属性。
  • DelegateBoilerEvent 类作为事件发布器,定义了 BoilerLogHandler 委托以及 BoilerEventLog 事件,在 LogProcess 方法中根据锅炉的温度和压力情况生成相应的备注信息,并通过 OnBoilerEventLog 方法触发事件传递相关日志信息。
  • BoilerInfoLogger 类用于将信息写入日志文件,实现了 IDisposable 接口来规范资源的释放。
  • RecordBoilerInfo 类作为事件订阅器,定义了 Logger 方法作为事件处理程序,在 Main 方法中进行订阅操作,使得当发布器触发事件时,一方面会在控制台输出日志信息,另一方面会将信息写入指定的日志文件中。

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词