C#事件订阅发布实现原理详解

C#事件订阅发布实现原理详解

一、事件订阅发布机制简介

事件是C#中最常用的一种机制之一,它可以将对象之间的通信极大地简化和解耦。订阅和发布是事件发生的关键步骤,其中订阅(或称为注册)表示一个对象准备接收来自另一个对象(即发布者)的通知,而发布(或称为引发)则表示对象触发了一个事件并向订阅该事件的其他对象发送通知。

在C#中,此机制通过event关键字来实现。当一个事件被声明为event时,它本质上是一个特殊的委托,而事件的引发则是通过委托的执行来实现的。因此,订阅者需要将它们的方法添加到事件的委托列表中,而发布者在事件被引发时将向该列表中的每个订阅者发送通知。

二、订阅发布机制的实现原理

事件的订阅和发布实现有多种方式,本文将介绍使用C#中的委托和事件机制实现订阅发布的方法。订阅发布机制的实现步骤如下:

1. 定义事件

在C#中,可以通过event关键字定义事件。例如:

public delegate void EventHandler(object sender, EventArgs e);

public class SomePublisher
{
    public event EventHandler SomeEvent;
}

以上代码定义了一个名为SomeEvent的事件,并将其类型定义为EventHandler,即一个具有两个参数(object类型和EventArgs类型)和无返回值的委托。在SomePublisher类中使用event关键字定义SomeEvent事件,并标识为公共事件,以允许其他类将其订阅。

2. 发布事件

发布(或引发)事件是通过调用类中的事件函数来实现的。例如:

public void DoSomething()
{
    OnSomeEvent(this, EventArgs.Empty);
}

protected virtual void OnSomeEvent(object sender, EventArgs e)
{
    SomeEvent?.Invoke(sender, e);
}

以上代码展示了在SomePublisher类中如何发布事件。在DoSomething方法中调用OnSomeEvent函数,将传递this作为调用者(即发布者),以及一个空的EventArgs参数(也可以使用自定义的事件参数类型)。OnSomeEvent方法是一个虚拟方法,允许派生类覆盖此方法以提供自己的实现。在其默认实现中,该方法使用条件运算符检查SomeEvent是否为空,以避免在无订阅事件的情况下引发空引用异常。如果SomeEvent不为空,则使用委托的Invoke方法向委托列表中的每个订阅者发送通知。

3. 订阅事件

订阅事件是将订阅者的方法添加到事件委托列表中的过程。以下是一个简单的示例:

public class SomeSubscriber
{
    public void SubscribeTo(SomePublisher publisher)
    {
        publisher.SomeEvent += HandleSomeEvent;
    }

    public void UnsubscribeFrom(SomePublisher publisher)
    {
        publisher.SomeEvent -= HandleSomeEvent;
    }

    private void HandleSomeEvent(object sender, EventArgs e)
    {
        Console.WriteLine("Some event occurred.");
    }
}

以上代码展示了一个名为SomeSubscriber的订阅者类,它定义了两个公共方法:SubscribeToUnsubscribeFrom,允许它将自己添加到和从订阅列表中删除。HandleSomeEvent方法是SomeEvent事件的处理函数,它将在事件被引发时执行。

三、示例说明

下面通过两个示例来说明事件订阅发布机制的使用方法。

示例1:使用事件机制实现线程通信

using System;
using System.Threading;

namespace EventDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var instance = new EventDemo();
            Thread thread = new Thread(delegate() { instance.DoWork(); });
            thread.Start();
            while (true)
            {
                Console.ReadLine();
                instance.Cancel();
            }
        }
    }
    public class EventDemo
    {
        public event EventHandler Done;
        private bool _cancelled;
        public void DoWork()
        {
            int count = 0;
            while (!_cancelled && count < 10)
            {
                count++;
                Console.WriteLine("Working... " + count);
                Thread.Sleep(1000);
            }
            if (!_cancelled)
            {
                OnDone(new EventArgs());
            }
            Console.WriteLine("Work done.");
        }
        protected virtual void OnDone(EventArgs e)
        {
            Done?.Invoke(this, e);
        }
        public void Cancel()
        {
            Console.WriteLine("Cancelling...");
            _cancelled = true;
        }
    }
}

以上示例展示了如何使用事件机制实现线程之间的通信。在EventDemo类中定义了一个名为Done的事件,表示已完成某项任务。在DoWork方法中,执行一些工作,如果_cancelled字段为false,则在工作完成时引发Done事件。为终止工作,我们可以在控制台上按回车键,然后调用Cancel方法来设置_cancelled字段为true,以立即取消操作。

在程序的主线程中,我们使用委托来开启一个新线程,开始执行DoWork方法。之后我们进入一个无限循环,等待在控制台上输入回车,然后结束工作并关闭线程。

示例2:使用事件机制实现对象通信

using System;

namespace EventDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var publisher = new SomePublisher();
            var subscriber1 = new SomeSubscriber("Subscriber 1");
            var subscriber2 = new SomeSubscriber("Subscriber 2");

            subscriber1.SubscribeTo(publisher);
            subscriber2.SubscribeTo(publisher);

            publisher.DoSomething();

            subscriber1.UnsubscribeFrom(publisher);
            publisher.DoSomething();
        }
    }

    public delegate void EventHandler(object sender, EventArgs e);

    public class SomePublisher
    {
        public event EventHandler SomeEvent;

        public void DoSomething()
        {
            OnSomeEvent(this, EventArgs.Empty);
        }

        protected virtual void OnSomeEvent(object sender, EventArgs e)
        {
            SomeEvent?.Invoke(sender, e);
        }
    }

    public class SomeSubscriber
    {
        private string _name;
        public SomeSubscriber(string name)
        {
            _name = name;
        }

        public void SubscribeTo(SomePublisher publisher)
        {
            publisher.SomeEvent += HandleSomeEvent;
        }

        public void UnsubscribeFrom(SomePublisher publisher)
        {
            publisher.SomeEvent -= HandleSomeEvent;
        }

        private void HandleSomeEvent(object sender, EventArgs e)
        {
            Console.WriteLine(_name + " received event.");
        }
    }
}

以上示例展示了如何使用事件机制实现简单的对象通信。在这个例子中,SomePublisher类定义了一个名为SomeEvent的事件,表示某些事件已发生。在DoSomething方法中,当操作完成时,将引发SomeEvent事件。SomeSubscriber类定义了一个构造函数,它允许为Subscriber指定名称,并且提供两个公共方法,SubscribeToUnsubscribeFrom,允许它将自己添加到和从订阅列表中删除。在HandleSomeEvent方法中,订阅者将收到事件并输出消息。

在程序的主线程中,我们创建一个SomePublisher对象和两个SomeSubscriber对象。两个订阅者都将publisher实例的SomeEvent事件添加到其订阅列表中。在调用publisherDoSomething方法时,两个订阅者的HandleSomeEvent方法都将被调用,并且两个订阅者将输出消息。之后,我们取消第一个订阅者,再次调用publisherDoSomething方法,只有第二个订阅者的HandleSomeEvent方法将被调用,输出消息。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#事件订阅发布实现原理详解 - Python技术站

(0)
上一篇 2023年6月6日
下一篇 2023年6月6日

相关文章

  • ASP.NET Core开发环境安装配置

    ASP.NET Core是一个跨平台的开源Web框架,用于构建现代化的Web应用程序。在本攻略中,我们将详细讲解如何安装和配置ASP.NET Core开发环境。 安装.NET Core SDK:首先,我们需要安装.NET Core SDK。我们可以从Microsoft官网下载并安装.NET Core SDK。安装完成后,我们可以在命令行中运行dotnet -…

    C# 2023年5月16日
    00
  • C# WebClient类用法实例

    C# WebClient类用法实例 简介 WebClient类是C#中提供的常用的网络编程类。它提供了以编程方式访问Web服务器资源的功能。利用WebClient对象,可以在应用程序中实现与HTTP,FTP和其他Internet协议的通信。 使用WebClient类下载文件 下面是一个示例,演示了如何使用WebClient类下载一个文件到本地。 using …

    C# 2023年6月1日
    00
  • .Net Core日志记录之日志配置

    .Net Core日志记录之日志配置 在 .Net Core 中进行日志记录,可以帮助我们更好地了解应用程序运行时的情况,以及修复可能出现的问题。本文介绍如何在 .Net Core 应用程序中配置日志记录。 1. 新建 .Net Core Web 应用程序 首先,我们需要创建一个基本的 .Net Core Web 应用程序。可以使用 Visual Studi…

    C# 2023年6月3日
    00
  • Unity 使用tiledmap解析地图的详细过程

    下面我将为你详细讲解Unity使用TiledMap解析地图的详细过程。 1. 安装TiledMap插件 首先需要在Unity中安装TiledMap插件,步骤如下: 进入Unity Asset Store,搜索“Tiled2Unity”并下载安装。 安装完成后,在Unity的菜单栏中选择“Tiled2Unity” > ”Import Tiled Map“…

    C# 2023年6月3日
    00
  • C#超市收银系统设计

    C#超市收银系统设计 C#超市收银系统设计是一款针对超市销售业务的收银软件。它可以帮助超市提高销售效率,减少错误率,优化管理流程,提升客户满意度。本文将对C#超市收银系统的设计过程进行详细的攻略说明。 设计需求分析 在进行软件设计前,我们需要进行需求分析,明确软件的设计目标、实现方法和功能特点。 软件目标:提供快速、准确、安全、高效的销售结算服务; 实现方法…

    C# 2023年6月7日
    00
  • .net实现文件读写的几种常用方法

    这里给出“.NET实现文件读写的几种常用方法”的攻略: 一、文件读写方式 在.NET中,实现文件读写主要有以下几种方式: 1.使用FileStream对象 FileStream是.NET中用于操作文件的类,可以使用Read方法读取文件,使用Write方法写入文件。 以下示例是使用FileStream实现写入文件和读取文件的方法: 写入文件 string fi…

    C# 2023年6月1日
    00
  • C#基础语法:Base关键字学习笔记

    标题:C#基础语法:Base关键字学习笔记 简介 C# 的 Base 关键字是一个重要的概念,在面向对象的编程中可以用来访问父类的成员或属性。本文将详细讲解 Base 关键字的用法及示例。 使用方式 Base 关键字可以用来调用父类中被隐藏的成员或者构造函数。 使用 Base 访问父类成员 当子类继承父类时,父类中的方法或属性在子类中可能会被重写或者被隐藏。…

    C# 2023年6月7日
    00
  • C#使用加边法计算行列式的值

    C#使用加边法计算行列式的值 什么是行列式? 在数学中,行列式是一个方阵所具有的一个标量值。行列式经常在线性代数、微积分和微分方程中出现,并且在工程、物理和计算机科学等领域也有广泛的应用。 加边法计算行列式 加边法是一种计算行列式的方法,通过对矩阵的某一行或某一列添加系数倍的另一行或另一列实现对行列式的求解。这种方法主要用于计算较小的矩阵,对于大的矩阵而言,…

    C# 2023年6月7日
    00
合作推广
合作推广
分享本页
返回顶部