【C#】EventHandler的使用

一、C#中EventHandler的使用详解

1.什么是EventHandler

EventHandler是.NET Framework中预定义的委托类型,专门用于表示不生成数据的事件的事件处理程序方法。它是事件处理模型的核心组件。

EventHandler的标准签名

cs 复制代码
public delegate void EventHandler(object sender, EventArgs e);
  • 第一个参数object sender - 事件源(引发事件的对象)
  • 第二个参数EventArgs e - 事件数据(如果事件不生成数据,则使用EventArgs.Empty

事件处理的基本流程

  1. 定义事件(发布者类中)
  2. 注册事件处理程序(订阅者类中)
  3. 触发事件(发布者类中)
  4. 处理事件(订阅者类中)

2.基本用法示例

1. 定义事件(发布者类)

cs 复制代码
public class Publisher
{
    // 定义事件 - 无数据事件
    public event EventHandler MyEvent;
    
    // 触发事件的方法(推荐使用空值检查)
    protected virtual void OnMyEvent()
    {
        MyEvent?.Invoke(this, EventArgs.Empty);
    }
    
    // 触发事件的公共方法
    public void TriggerEvent()
    {
        OnMyEvent();
    }
}

2. 定义事件处理程序(订阅者类)

cs 复制代码
public class Subscriber
{
    public void HandleMyEvent(object sender, EventArgs e)
    {
        Console.WriteLine("事件已触发!");
        // 可以访问sender对象,如:((Publisher)sender).SomeProperty
    }
}

3. 事件注册与触发

cs 复制代码
public class Program
{
    static void Main()
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();
        
        // 注册事件处理程序
        publisher.MyEvent += subscriber.HandleMyEvent;
        
        // 触发事件
        publisher.TriggerEvent();
        
        // 可选:移除事件处理程序
        publisher.MyEvent -= subscriber.HandleMyEvent;
    }
}

3.泛型版本:EventHandler

当事件需要传递自定义数据时,应使用泛型版本EventHandler<TEventArgs>

cs 复制代码
// 自定义事件参数类
public class CustomEventArgs : EventArgs
{
    public string Message { get; set; }
    public int Value { get; set; }
}

// 发布者类
public class DataPublisher
{
    public event EventHandler<CustomEventArgs> DataProcessed;
    
    protected virtual void OnDataProcessed(CustomEventArgs e)
    {
        DataProcessed?.Invoke(this, e);
    }
    
    public void ProcessData(string message, int value)
    {
        // 处理数据...
        OnDataProcessed(new CustomEventArgs { Message = message, Value = value });
    }
}

// 订阅者
public class DataSubscriber
{
    public void HandleDataProcessed(object sender, CustomEventArgs e)
    {
        Console.WriteLine($"收到数据: {e.Message}, 值: {e.Value}");
    }
}

4.常见使用技巧与注意事项

1. 空值检查(避免NullReferenceException)

cs 复制代码
// 错误示范(可能导致异常)
MyEvent(this, EventArgs.Empty); 

// 正确做法(空值检查)
MyEvent?.Invoke(this, EventArgs.Empty);

2. 事件线程安全(多线程环境)

cs 复制代码
// 线程安全的事件触发
var handler = Volatile.Read(ref MyEvent);
handler?.Invoke(this, EventArgs.Empty);

3. 使用Lambda表达式注册事件

cs 复制代码
publisher.MyEvent += (sender, e) => 
{
    Console.WriteLine("通过Lambda处理事件");
};

4. 事件注销(避免内存泄漏)

cs 复制代码
// 在订阅者销毁时注销事件
public class Subscriber : IDisposable
{
    private Publisher _publisher;
    
    public Subscriber(Publisher publisher)
    {
        _publisher = publisher;
        _publisher.MyEvent += HandleEvent;
    }
    
    public void Dispose()
    {
        _publisher.MyEvent -= HandleEvent;
    }
    
    private void HandleEvent(object sender, EventArgs e)
    {
        // 事件处理逻辑
    }
}

5.与委托的关系

  • 事件本质上是封装了委托的类成员,提供了对委托的结构化访问
  • 事件只允许添加、删除或调用事件处理程序,不能直接访问底层委托
  • 事件提供了更安全的事件处理机制,避免了直接操作委托可能带来的问题

6.总结

EventHandler是C#中处理事件的标准委托类型,使用它可以使代码更加清晰、安全和可维护。在实际应用中,应:

  1. 对于无数据事件,使用EventHandler
  2. 对于需要传递数据的事件,使用EventHandler<TEventArgs>
  3. 始终进行空值检查
  4. 在适当的时候注销事件处理程序,避免内存泄漏

通过合理使用EventHandler,可以实现发布者和订阅者之间的松耦合通信,这是C#事件模型的核心思想。

二、EventHandler与Event、EventWaitHandle得区别以及联系?

1. 概念定义

EventHandler

  • 类型:.NET中预定义的委托类型
  • 作用:表示不生成数据的事件的事件处理程序方法
  • 签名public delegate void EventHandler(object sender, EventArgs e);
  • 使用场景:用于定义事件处理程序的方法签名
  • 关键点:是事件处理的"方法签名规范"

Event

  • 类型:C#关键字
  • 作用:用于声明事件,是委托类型的特殊包装
  • 使用方式public event EventHandler MyEvent;
  • 关键点 :提供安全的事件注册机制,只能使用+=-=操作,不能直接赋值

EventWaitHandle

  • 类型 :.NET Framework中的类(位于System.Threading命名空间)
  • 作用:用于线程同步,表示系统事件
  • 主要类型
    • AutoResetEvent:自动重置事件
    • ManualResetEvent:手动重置事件
  • 关键点:用于多线程环境中的线程同步,与事件处理无关

2. 区别对比

特性 EventHandler Event EventWaitHandle
本质 委托类型 C#关键字 .NET类
命名空间 System C#语言特性 System.Threading
主要用途 事件处理程序的签名规范 事件声明 线程同步
使用方式 作为委托类型使用 public event EventHandler MyEvent; EventWaitHandle event = new AutoResetEvent(false);
与事件处理的关系 事件处理程序的签名 事件声明 无直接关系
是否用于事件处理

3. 详细解释与联系

EventHandler 和 Event 的联系

  • 紧密关系EventHandlerevent最常用的委托类型

  • 典型用法

cs 复制代码
public class Publisher
{
    // 使用EventHandler作为委托类型定义事件
    public event EventHandler MyEvent;
    
    protected virtual void OnMyEvent()
    {
        MyEvent?.Invoke(this, EventArgs.Empty);
    }
}
  • 为什么需要Event :直接使用委托类型(如EventHandler)作为事件成员,会导致订阅者可以随意赋值,破坏事件处理的安全性。event关键字限制了只能通过+=-=来添加和移除事件处理程序。

EventHandler 和 EventWaitHandle 的区别

  • 完全不同的概念
    • EventHandler用于UI事件、自定义事件处理
    • EventWaitHandle用于线程同步,与事件处理机制无关
  • 应用场景
    • EventHandler:按钮点击、数据变化等UI事件
    • EventWaitHandle:线程间通信、等待特定条件满足

Event 和 EventWaitHandle 的区别

  • Event:C#语言特性,用于实现发布-订阅模式
  • EventWaitHandle:.NET类库中的同步原语,用于线程同步
  • 无直接联系:它们解决的是完全不同的问题

4. 实际使用示例

EventHandler + Event (事件处理)

cs 复制代码
public class Button
{
    public event EventHandler Click;
    
    public void OnClick()
    {
        Click?.Invoke(this, EventArgs.Empty);
    }
}

public class Form
{
    public void Initialize()
    {
        Button button = new Button();
        // 使用EventHandler注册事件处理
        button.Click += (sender, e) => Console.WriteLine("Button clicked!");
    }
}

EventWaitHandle (线程同步)

cs 复制代码
// 创建事件
AutoResetEvent autoEvent = new AutoResetEvent(false);

// 线程1:等待事件
Thread thread1 = new Thread(() =>
{
    Console.WriteLine("Thread 1: Waiting for event...");
    autoEvent.WaitOne();
    Console.WriteLine("Thread 1: Event received!");
});

// 线程2:触发事件
Thread thread2 = new Thread(() =>
{
    Thread.Sleep(2000);
    Console.WriteLine("Thread 2: Setting event...");
    autoEvent.Set();
});

thread1.Start();
thread2.Start();

5. 总结

  • EventHandler是事件处理程序的签名规范,是一个委托类型
  • Event是C#关键字,用于声明事件,提供安全的事件注册机制
  • EventWaitHandle是.NET中用于线程同步的类,与事件处理机制无关

关键区别

  • EventHandlerevent事件处理机制的核心组成部分
  • EventWaitHandle线程同步机制的一部分,与事件处理无关

简单记忆

  • 事件处理(UI事件、自定义事件)用 EventHandler + event
  • 线程同步用 EventWaitHandle(AutoResetEvent/ManualResetEvent)

这三者在.NET框架中都与"事件"有关,但解决的是完全不同的问题,不能混淆使用。

三、其他

【C#】Event的使用

【C#】EventWaitHandle的用法

相关推荐
唐青枫3 小时前
C#.NET Cronos 实战:优雅解析与执行 Cron 表达式
c#·.net
周杰伦fans8 小时前
C# SelectMany 完全指南:从入门到精通
c#·linq
weixin_307779139 小时前
C#程序实现将Teradata的存储过程转换为Azure Synapse Dedicated SQL pool的存储过程
数据库·数据分析·c#·云计算·azure
Aevget10 小时前
界面控件DevExpress WPF v25.2预览 - 模板工具包全新升级
c#·wpf·界面控件·devexpress·ui开发
TheWindofFate11 小时前
C# List集合
c#·list
星河队长12 小时前
C#实现智能提示输入,并增色显示
开发语言·c#
海木漄13 小时前
C# 内存是绝对自动清理吗?
开发语言·c#
我是唐青枫13 小时前
C#.NET PeriodicTimer 深入解析:高效异步定时器的正确打开方式
c#·.net
技术支持者python,php14 小时前
ModbusRtc与ModbusTCP,esp32
c#