C# 中的事件:何时使用以及如何实现它们

作者:微信公众号:【架构师老卢】
2-15 10:40
104

欢迎!您可能已经听说过很多有关 C# 事件的信息,但您想知道,它们是如何联系在一起的?请坐下来,因为在本文中,您将了解有关 C# 事件及其应用程序的所有详细信息。

这就像学习演奏乐器;在开始作曲之前,您需要了解如何阅读音符。在深入研究高级内容之前,让我们先了解一下基础知识。跟着我,我保证,你会写出迷人的交响曲——我的意思是,很快就能用 C# 编码了!

C# 事件简介

等等,C# 事件到底是什么?秘密行动?不!在 C# 的世界中,事件只是类在发生感兴趣的事情时通知其他类或对象的一种方式。

C 中的事件概述#

C# 上下文中的事件。想象一下,你正在听音乐会。演奏的乐队是事件(C# 类)的发布者,而观众(其他类或对象)正在等待值得注意的事情(事件)发生。当乐队开始演奏(事件发生)时,观众会做出反应(对事件做出反应)。在编程术语中,C# 中的事件在对象中发生特定操作时提供通知。

public class AlarmClock  
{  
    public event Action AlarmSounded;  
    public void Start()  
    {  
        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));  
        AlarmSounded?.Invoke();  
    }  
}  
  
public class Person  
{  
    public void WakeUp() => Console.WriteLine("Waking Up!");  
}  
  
public class MainProgram  
{  
    public static void Main()  
    {  
        AlarmClock alarmClock = new AlarmClock();  
        Person person = new Person();  
        alarmClock.AlarmSounded += person.WakeUp;  
        alarmClock.Start();  
    }  
}

在此代码片段中,该类发布该类侦听的事件。当事件在 5 秒后触发时,该人的唤醒方法将响应。AlarmClockAlarmSoundedPersonAlarmSounded

事件处理程序在 C 中的作用#

在节日中,活动组织者会处理所有事情,对吧?同样,在 C# 中,事件处理程序处理对事件的响应。

什么是 C 中的事件处理程序#

在 C# 事件处理中,“事件处理程序”是在触发给定事件时调用的委托。就像侦听器正在等待播放自己喜欢的歌曲一样,事件处理程序正在等待正确的事件执行操作。

public class Button  
{  
    public event EventHandler Clicked;  
    public void PressButton()  
    {  
        Clicked?.Invoke(this, EventArgs.Empty);  
    }  
}  
  
public class User  
{  
    public void PerformAction()  
    {  
        Console.WriteLine("Action Performed!");  
    }  
}  
public class MainProgram  
{  
    public static void Main()  
    {  
        Button button = new Button();  
        User user = new User();  
        button.Clicked += user.PerformAction;  
        button.PressButton();  
    }  
}

在上面的示例中,该类具有一个用作事件处理程序的方法。每当按下 (事件发生)时,用户都会执行特定操作。UserPerformActionButton

在 C 语言中实现事件#

啊!任何编程语言的实用方面,这才是真正的乐趣开始的地方,不是吗?是时候采取行动了,看看我们如何在 C# 中实现事件。让我们卷起袖子,潜入编码部分!

在 C 语言中实现事件的分步指南#

在 C# 中实现事件就像分步编排程序中响应某些操作的时间和方式。请记住,这是一段最好一步一步的旅程。让我们分解一下这个过程:

  • 定义与要使用的事件处理程序方法的签名匹配的委托。
  • 使用您定义的委托声明事件。
  • 在提供程序类中实现引发事件的方法。
  • 在订阅者类中创建一个方法,该方法将处理事件(符合委托)。
  • 将事件处理方法订阅到事件。

听起来很多?让我们用一个真实的例子来简化这一点。

真实世界的 C# 事件示例

我们考虑一个红绿灯系统怎么样?灯光变化(事件)会导致汽车做出相应的反应(事件处理)。以下是如何对其进行编码的简化版本:

// step 1: define a delegate  
public delegate void TrafficLightChangedHandler(string color);  
  
public class TrafficLight  
{  
    // step 2: declare an event  
    public event TrafficLightChangedHandler TrafficLightChanged;  
    public void ChangeLight(string color)  
    {  
        // step 3: method that raises the event  
        Console.WriteLine($"The traffic light is {color}.");  
        TrafficLightChanged?.Invoke(color);  
    }  
}  
public class Car  
{  
    public void ReactToLight(string lightColor)  
    {  
        // step 4: event handling method  
        if (lightColor == "Red")  
        {  
            Console.WriteLine("Car stops.");  
        }  
        else if (lightColor == "Green")  
        {  
            Console.WriteLine("Car starts moving.");  
        }  
    }  
}  
public class MainProgram  
{  
    public static void Main(string\[\] args)  
    {  
        TrafficLight light = new TrafficLight();  
        Car car = new Car();  
        // step 5: subscribe to the event  
        light.TrafficLightChanged += car.ReactToLight;  
        light.ChangeLight("Green");  
        light.ChangeLight("Red");  
    }  
}

在上面的代码中,当交通信号灯颜色发生变化时,事件被触发并导致汽车做出反应。如果绿灯亮起,则汽车行驶;如果是红色的,则汽车停下来。TrafficLightChanged

让我们回到电子邮件发送示例。除了发送电子邮件外,我们可能还需要向收件人确认正在发送电子邮件。

public class Recipient  
{  
    public void OnAcknowledge(string recipient)  
    {  
        Console.WriteLine($"Email is being sent to {recipient}");  
    }  
}  
public class MainProgram  
{  
    public static void Main(string[] args)  
    {  
        EmailAcknowledge emailAck = new EmailAcknowledge();  
        Recipient recipient = new Recipient();  
        emailAck.AcknowledgeSending += recipient.OnAcknowledge;  
        emailAck.Acknowledge("Bob");  
        emailAck.Acknowledge("Alice");  
    }  
}

在新引入的代码片段中,当调用类中的方法时,它会引发该类正在侦听的事件。一旦引发此事件,就会调用类中的方法并打印收件人的姓名。AcknowledgeEmailAcknowledgeAcknowledgeSendingRecipientOnAcknowledgeRecipient

在 C 语言中使用 EventArgs#

呼!你已经走得很远了。下一站是城镇。准备?EventArgs

了解 C# 事件参数

在 C# 中,“EventArgs”是一个提供与事件相关的数据的类。将 EventArgs 视为传递事件发生消息的信使。

public class SongPlayedEventArgs : EventArgs  
{  
    public string PlayedSong { get; set; }  
}  
  
public class MusicPlayer  
{  
    public event EventHandler<SongPlayedEventArgs> SongPlayed;  
    public void PlaySong(string song)  
    {  
        SongPlayed?.Invoke(this, new SongPlayedEventArgs() { PlayedSong = song });  
    }  
}  
  
public class Listener  
{  
    public void OnSongPlayed(object sender, SongPlayedEventArgs e)  
    {  
        Console.WriteLine($"'{e.PlayedSong}' has been played.");  
    }  
}

在此示例中,携带已播放歌曲的名称。 使用此自定义数据 () 来响应事件。SongPlayedEventArgsListenerPlayedSongSongPlayed

C# 事件处理中的高级概念

深吸一口气,如果需要的话,喝杯咖啡,因为我们即将更深入地研究 C# 事件的深渊。就像建造一座高耸的乐高摩天大楼一样,这一切都是为了了解有效组装积木的复杂性和技术。

安全事件调用

C# 中事件处理的一个重要方面是始终确保安全的事件调用。侦听器类可能会在任何给定时间点取消订阅事件。在没有任何订阅侦听器的情况下调用事件可能会导致空引用异常 — 相信我,我们不喜欢这些,不是吗?

以下是安全调用事件的方法:

public class Publisher  
{  
    public event EventHandler<EventArgs> OnPublish;  
    public void Publish()  
    {  
        OnPublish?.Invoke(this, EventArgs.Empty);  
    }  
}

该语法是 C# 在调用事件处理程序之前进行 null 检查的快捷方式,使我们免于可能的 null 引用异常。就好像您在按下冲泡按钮之前检查咖啡机是否确实存在一样。?.

使用自定义 EventArgs 传递数据

在许多情况下,我们需要将一些数据与事件一起传递。这就是自定义 EventArgs 的用武之地。

假设您正在为图书馆构建一个应用程序,每当有新书到达时,该应用程序就会触发一个事件。

public class NewBookEventArgs : EventArgs  
{  
    public string Title { get; set; }  
    public string Author { get; set; }  
}  
  
public class Library  
{  
    public event EventHandler<NewBookEventArgs> OnNewBookArrived;  
    public void AddBook(string title, string author)  
    {  
        OnNewBookArrived?.Invoke(this, new NewBookEventArgs { Title = title, Author = author });  
    }  
}  
  
public class Member  
{  
    public void OnNewBookArrived(object sender, NewBookEventArgs e)  
    {  
        Console.WriteLine($"New book arrived! Title: {e.Title}, Author: {e.Author}");  
    }  
}

在这里,我们创建了一个继承并添加了两个属性的类:和 。我们通过创建一个新实例并将其与事件调用一起传递来触发事件。NewBookEventArgsEventArgsTitleAuthorNewBookEventArgs

这样,事件处理程序(如来自类的事件处理程序)可以访问此数据并采取相应的行动。OnNewBookArrivedMember

取消订阅事件

事情是这样的:每次类订阅一个事件时,它都会与事件源形成一个强引用。此引用可以阻止垃圾回收器回收内存,从而导致潜在的内存泄漏(又名静默资源杀人者!

就像您在离开房间之前关灯或取消订阅收件箱中烦人的时事通讯一样,请记住在不再需要活动时取消订阅活动。

public class Publisher  
{  
    public event Action OnPublish;  
}  
  
public class Subscriber  
{  
    public void OnPublishing()  
    {  
        Console.WriteLine("Something has been published!");  
    }  
    public void Register(Publisher publisher)  
    {  
        publisher.OnPublish += OnPublishing;  
    }  
    public void Unregister(Publisher publisher)  
    {  
        publisher.OnPublish -= OnPublishing;  
    }  
}  
  
public static class Program  
{  
    public static void Main()  
    {  
        Publisher publisher = new Publisher();  
        Subscriber subscriber = new Subscriber();  
        subscriber.Register(publisher);  // Subscribing to the event  
        publisher.OnPublish?.Invoke();    
        subscriber.Unregister(publisher); // Unsubscribing from the event  
        publisher.OnPublish?.Invoke();   
    }  
}

和 方法处理事件的订阅和取消订阅。很简单,对吧?是的,这就像您同意接收这些营销电子邮件一样。当你决定你已经受够了吗?只需取消订阅!RegisterUnregisterpublisher.OnPublish

事件和 C# 编程的未来

哇,真是一段旅程,对吧?活动是否成为您最好的新朋友?它们应该,因为将行为封装到事件中可以简化您的代码,使其更干净、更高效。现在这似乎是一个挑战,但你越是冥想这些知识,就越容易掌握它的本质。

相关留言评论
昵称:
邮箱:
阅读排行