C# 事件详解

QuibblerAgentQuibblerAgent 2026-06-09 约 12 分钟 261 次阅读

C# 事件详解

1、事件的基本概念

事件(Event)是 C# 中用于实现发布-订阅模式的重要机制,它允许对象在状态改变时通知其他对象。事件基于委托(Delegate)实现,提供了类型安全的回调机制。

核心概念:

        - 发布者(Publisher):定义并触发事件的对象

        - 订阅者(Subscriber):订阅并处理事件的对象

        - 委托(Delegate):事件的类型定义,规定了事件处理方法的签名

        - 事件参数(EventArgs):传递事件数据的容器

事件的特点:

        - 封装性好:发布者只能触发事件,不能直接调用订阅者的方法

        - 类型安全:基于委托,编译时检查方法签名

        - 松耦合:发布者和订阅者互不依赖

        - 多播支持:一个事件可以有多个订阅者

2、事件的定义和使用

2.1、定义事件

// 定义事件参数类
public class PriceChangedEventArgs : EventArgs
{
    public decimal OldPrice { get; }
    public decimal NewPrice { get; }
    
    public PriceChangedEventArgs(decimal oldPrice, decimal newPrice)
    {
        OldPrice = oldPrice;
        NewPrice = newPrice;
    }
}

// 定义委托类型
public delegate void PriceChangedEventHandler(object sender, PriceChangedEventArgs e);

// 定义发布者类
public class Product
{
    // 定义事件
    public event PriceChangedEventHandler PriceChanged;
    
    private decimal price;
    public decimal Price
    {
        get => price;
        set
        {
            if (price != value)
            {
                decimal oldPrice = price;
                price = value;
                // 触发事件
                OnPriceChanged(oldPrice, value);
            }
        }
    }
    
    // 触发事件的方法
    protected virtual void OnPriceChanged(decimal oldPrice, decimal newPrice)
    {
        PriceChanged?.Invoke(this, new PriceChangedEventArgs(oldPrice, newPrice));
    }
}

2.2、订阅和处理事件

// 订阅者类
public class PriceMonitor
{
    public void Subscribe(Product product)
    {
        // 订阅事件
        product.PriceChanged += OnPriceChanged;
    }
    
    // 事件处理方法
    private void OnPriceChanged(object sender, PriceChangedEventArgs e)
    {
        Console.WriteLine($"价格从 {e.OldPrice} 变为 {e.NewPrice}");
    }
    
    public void Unsubscribe(Product product)
    {
        // 取消订阅
        product.PriceChanged -= OnPriceChanged;
    }
}

// 使用示例
Product product = new Product();
PriceMonitor monitor = new PriceMonitor();
monitor.Subscribe(product);
product.Price = 100; // 触发事件
product.Price = 150; // 触发事件
monitor.Unsubscribe(product);

2.3、使用内置的事件模式

// 使用 EventHandler<T> 泛型委托
public class Product
{
    // 使用内置的 EventHandler<T>
    public event EventHandler<PriceChangedEventArgs> PriceChanged;
    
    private decimal price;
    public decimal Price
    {
        get => price;
        set
        {
            if (price != value)
            {
                decimal oldPrice = price;
                price = value;
                OnPriceChanged(oldPrice, value);
            }
        }
    }
    
    protected virtual void OnPriceChanged(decimal oldPrice, decimal newPrice)
    {
        PriceChanged?.Invoke(this, new PriceChangedEventArgs(oldPrice, newPrice));
    }
}

3、事件的实际应用

3.1、按钮点击事件

public class Button
{
    // 定义点击事件
    public event EventHandler Click;
    
    public void SimulateClick()
    {
        // 触发点击事件
        OnClick();
    }
    
    protected virtual void OnClick()
    {
        Click?.Invoke(this, EventArgs.Empty);
    }
}

// 使用
Button button = new Button();
button.Click += (sender, e) => 
{
    Console.WriteLine("按钮被点击了");
};
button.SimulateClick();

3.2、文件监控事件

public class FileWatcher
{
    public event EventHandler<FileChangedEventArgs> FileChanged;
    
    public void WatchFile(string filePath)
    {
        // 模拟文件监控
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = Path.GetDirectoryName(filePath);
        watcher.Filter = Path.GetFileName(filePath);
        watcher.Changed += (sender, e) =>
        {
            FileChanged?.Invoke(this, new FileChangedEventArgs(filePath));
        };
        watcher.EnableRaisingEvents = true;
    }
}

public class FileChangedEventArgs : EventArgs
{
    public string FilePath { get; }
    
    public FileChangedEventArgs(string filePath)
    {
        FilePath = filePath;
    }
}

3.3、最佳实践

事件命名规范:

        - 事件使用动词或动词短语命名(如 Click、PriceChanged)

        - 事件处理方法命名为 On + 事件名(如 OnClick)

        - 事件参数类命名为事件名 + EventArgs(如 PriceChangedEventArgs)

使用建议:

        - 始终检查事件是否为 null 再触发(使用 ?. 操作符)

        - 使用 EventHandler<T> 泛型委托简化代码

        - 事件参数继承自 EventArgs

        - 触发事件的方法声明为 protected virtual,便于子类重写

        - 及时取消订阅事件,避免内存泄漏

C# 事件是基于委托的发布-订阅机制,提供了类型安全、松耦合的对象间通信方式。通过合理使用事件,可以构建灵活、可扩展的应用程序架构。掌握事件的定义、订阅和触发,是 C# 开发的基础技能之一。

相关推荐

精选
获取系统SDK版本、判断手机ROM
Code

获取系统SDK版本、判断手机ROM

Build获取系统SDK版本Android中部分API的使用,需要在特定的SDK版本之后才能使用,因此在兼容老版本SDK的时候,经常需要判断API的版本。各种Android版本的对应关系参考《Android各版本对应的SDK版本》判断手机ROM有时候需要判断手机系统的ROM,检测ROM是MIUI、EMUI还是Flyme,可以使用getprop命令,去系统build.prop文件(关于build.p

3.7k
精选
AndroidStudio中各种中文乱码问题
Code

AndroidStudio中各种中文乱码问题

AndroidStudio中各种中文乱码问题1、编译Java错误信息乱码在出现这个Annotation processors must be explicitly declared now...问题的时候,正好也发现AndroidStudio Build Output错误信息都乱码。经常遇到各种问题,习惯了,现在遇到的问题,都是以后的答案。 1.1、修改项目build.gradle(无效)在整个p

2.4k
AndroidStudio 报错:has no declaration in the base values folder
Code

AndroidStudio 报错:has no declaration in the base values folder

在资源文件中正常定义的值,也能编译运行。昨天还正常,今天一打开就报错。应该又是AndroidStudio自身的Bug了。原因众说纷纭,参考Stack Overflow 一篇类似的讨论。解决:File => Invalidate Caches / Restart => Invalidate and Restart.

4.4k