【C#进阶】C# 事件

这篇具有很好参考价值的文章主要介绍了【C#进阶】C# 事件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

序号 系列文章
15 【C#进阶】C# 属性
16 【C#进阶】C# 索引器
17 【C#进阶】C# 委托

前言

🌍 hello大家好啊,我是哈桑。本文为大家介绍 C# 中的事件。


1、什么是事件

事件本质上来讲是一种特殊的多播委托1,只能从声明它的类中进行调用。事件通常用于表示用户操作,例如单击按钮或图形用户界面中的菜单选项。C# 中常常会使用事件来实现线程之间的通信。

1.1、发布订阅模型的说明

在 C# 中,类或对象可以通过事件向其他类或对象通知发生的相关事情。这种模式通常称为发布订阅模型,发送(或引发)事件的类称为“发布者”,接收(或处理)事件的类称为“订阅者”。

对发布者和订阅者的解释说明:

发布者: 一个创建了事件和委托定义的对象,同时也包含了事件和委托之间的联系与具体行为。发布者的任务就是执行这些事件,并通知程序中的其它对象。
订阅者: 一个接收事件并提供事件处理程序的对象。订阅者中的方法(事件处理程序)用于分配给发布者中的委托。
简单的来说,发布者确定何时引发事件,而订阅者确定对事件作出何种响应。

代码示例:(简单实现)

using System; 

// 发布者类 
public class PublisherClass
{
    // 和事件搭配的委托
    public delegate void PubDelegate();

    // 定义事件 
    public event PubDelegate PubEvent;

    // 编写处理事件的具体逻辑
    public void EventHandling()
    {
        if (PubEvent == null)
        {
            Console.WriteLine("需要注册事件的啊");
        }
        else
        {
            // 执行注册的事件 
            PubEvent(); 
        }
    }
}

// 订阅者类 
public class SubscriberClass
{
    public void printout()
    {
        Console.WriteLine("执行了订阅者类中的事件。");
        Console.ReadLine(); 
    }
}

public class Program
{
    static void Main()
    {
        // 实例化对象 
        PublisherClass p = new PublisherClass();
        SubscriberClass s = new SubscriberClass();
        // 执行事件 
        p.EventHandling();
        // 注册事件 
        p.PubEvent += new PublisherClass.PubDelegate(s.printout); 
        // 执行事件 
        p.EventHandling();  
    }
}

运行结果:
c#事件,C#/.NET系列文章,c#,开发语言,.net,.netcore,微软
在上例中,创建了发布者类 PublisherClass 和订阅者类 SubscriberClass,直接把订阅者类中的 printout 方法传递给了 PublisherClass.PubEvent 方法用于执行。(发布订阅模型的简单思路就是这样, 在正式的项目中程序之间的交互与通信表现得更加复杂。)

2、事件的声明

首先需要注意的是,因为事件的本质还是委托,所以要声明一个事件之前必须先声明一个相对应的委托。

以上面示例的代码来说明:

// 和事件搭配的委托
public delegate void PubDelegate();

在 C# 中,事件需要使用关键字 event,事件的声明语法可以总结为如下所示:

<Access Specifier > event <Delegate> <Event Name>

  • Access Specifier: 访问说明符
  • event: 声明事件必须要有的关键字
  • Delegate: 分配给事件的委托(事先声明好的)
  • Event Name: 事件的名称

示例代码:

// 定义事件 
public event PubDelegate PubEvent;

3、事件的使用

事件的基本使用在上面的发布订阅模型的说明中已经演示了,这里不再赘述。接下来以一个新的示例来说明事件在基类、接口中的定义和如何自定义方法访问事件的操作。

3.1、使用基类中的事件

子类可以继承使用基类中已经声明的事件,像这种使用基类中的事件的模式广泛用于 .NET 类库中的 Windows 窗体2类。 以一个简单的程序来演示子类如何使用基类中的事件。

代码示例:

namespace BaseClassEvents 
{
    using System;

    // 基类事件发布者
    public abstract class Shape
    {
        protected double _area;

        public double Area
        {
            get { return _area; }
            set { _area = value; }
        }

        // 声明一个与事件搭配的委托
        public delegate void ShapeDelegate();

        // 声明基类中的事件 
        public event ShapeDelegate ShapeEvent;

        // 抽象方法
        public abstract void Drow();
        public abstract void GetArea();

        // 执行已经注册的事件 
        public void EventHandling()
        {
            if (ShapeEvent != null)
            {
                ShapeEvent();
            }
            else
            {
                Console.WriteLine("需要注册事件的");
            }
        }
    }

    // 圆形 
    public class Circle : Shape
    {
        private double _radius;

        public Circle(double radius)
        {
            _radius = radius;
            _area = 3.14 * _radius * _radius;
        }

        public override void Drow()
        {
            Console.WriteLine("绘制了一个圆形");
        }

        public override void GetArea()
        {
            Console.WriteLine($"圆形的面积为{Area}");
        }
    }

    // 矩形
    public class Rectangle : Shape
    {
        private double _length;
        private double _width;

        public Rectangle(double length, double width)
        {
            _length = length;
            _width = width;
            _area = _length * _width;
        }

        public override void Drow()
        {
            Console.WriteLine("绘制了一个矩形");
        }

        public override void GetArea()
        {
            Console.WriteLine($"矩形的面积为{Area}");
        }
    }

    // 将形状的行为添加道基类的事件里去 
    public class ShapeContainer
    {
        public void AddMethod(Shape shape)
        {
            shape.ShapeEvent += shape.Drow;
            shape.ShapeEvent += shape.GetArea;

            // 执行基类中已经注册的事件 
            shape.EventHandling();
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            var circle = new Circle(11);
            var rectangle = new Rectangle(11, 11);
            var container = new ShapeContainer();

            container.AddMethod(circle);
            container.AddMethod(rectangle);
        }
    }
}

运行结果:
c#事件,C#/.NET系列文章,c#,开发语言,.net,.netcore,微软在上面的示例中,创建了 Circle 和 Rectangle 两个形状类并继承了 Shape 基类, 在 ShapeContainer.AddMethod 方法中使用 shape 参数将指定类方法添加基类的 ShapeEvent 事件中,这样就可以在子类中使用基类中的 EventHandling 方法,以此达到使用基类中的事件的目的。

3.2、接口中定义事件

不仅是在类中,在接口中也可以声明事件,称为接口事件。接口事件的实现和接口上的方法或属性的实现是一样的,以一个示例来说明如何在类中实现接口事件。

代码示例:

namespace ImplementInterfaceEvents
{
    public interface IDrawingObject
    {
        // 所有继承该接口的对象都需要创建 ShapeChanged 事件
        event EventHandler ShapeChanged;        
    }

    public class MyEventArgs : EventArgs
    {
        // 构造方法 
        public MyEventArgs()
        {
            Console.WriteLine("执行了 MyEventArgs 类");
        }
    }

    public class Shape : IDrawingObject
    {
        public event EventHandler ShapeChanged;

        public void ChangeShape()
        {
            // 在活动开始前做点什么… 
            MyEventArgs m = new MyEventArgs();

            OnShapeChanged(m);
            // 或者事后在这里做点什么。 
        }

        protected virtual void OnShapeChanged(MyEventArgs e)
        {
            ShapeChanged?.Invoke(this, e);
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            Shape s = new Shape();
            s.ChangeShape();
        }
    }
}

运行结果:
c#事件,C#/.NET系列文章,c#,开发语言,.net,.netcore,微软
在上面的示例,Shape 类继承 IDrawingObject 接口并实现了 ShapeChanged 事件。在 ChangeShape 方法中将 MyEventArgs 方法注册到了 ShapeChanged 事件中并调用。

3.3、自定义方法访问事件

在大多数情况下,是无需提供自定义事件访问器的。但是某些特殊情况下,就需要自定义事件访问器,比方说当类继承自两个或多个接口,且每个接口都具有相同名称的事件。这时就必须为至少其中一个事件提供显式接口实现。 为事件编写显式接口实现时,还必须编写 add 和 remove 事件访问器。当遇到这种情况时就需要自己定义一个事件访问器。

通过提供自己的访问器,可以指定两个事件是由类中的同一个事件表示,还是由不同事件表示。 例如,如果根据接口规范应在不同时间引发事件,可以在类中将每个事件与单独实现关联。

代码示例:

namespace ImplementInterfaceEvents
{
    public interface IDrawingObject
    {
        // 所有继承该接口的对象都需要创建 ShapeChanged 事件
        event EventHandler ShapeChanged;
    }

    public class MyEventArgs : EventArgs
    {
        // 构造方法 
        public MyEventArgs()
        {
            Console.WriteLine("执行了 MyEventArgs 类");
        }
    }

    public class Shape : IDrawingObject
    {
        //为每个接口事件创建一个事件 
        event EventHandler DrawEvent;

        // 自定义实现 
        event EventHandler IDrawingObject.ShapeChanged
        {
            add { DrawEvent += value; }
            remove { DrawEvent -= value; }
        }

        public void ChangeShape()
        {
            // 在活动开始前做点什么… 
            MyEventArgs m = new MyEventArgs();
            OnShapeChanged(m);
            // 或者事后在这里做点什么。 
        }

        protected virtual void OnShapeChanged(MyEventArgs e)
        {
            DrawEvent?.Invoke(this, e);
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            Shape s = new Shape();
            s.ChangeShape();
        }
    }
}

在接口事件的示例基础上进行的改动:
c#事件,C#/.NET系列文章,c#,开发语言,.net,.netcore,微软
点击了解更多自定义事件访问器的使用。

4、事件与委托的异同:

  • 相同点:
    • 事件其实是一个多播委托,本质上是一样的。
  • 不同点:
    • 可调用位置不同:事件只能在声明事件的类中才能调用,而委托无论是在类的内部还是外部都可以调用。
    • 可使用符号不同:事件只能使用 += 和 -= 符号来订阅和取消订阅,但是委托不仅可以使用 += 和 -= 符号还可以使用 = 符号进行方法分配。

点击了解更多事件的使用。


结语

🌎 以上就是 C# 事件的介绍啦,希望对大家有所帮助。感谢大家的支持。


  1. 多播委托: 就是一个委托同时绑定多个方法,多播委托也叫委托链,委托组合。 ↩︎

  2. Windows 窗体: Windows 窗体是用于生成 Windows 桌面应用的 UI 框架。 ↩︎文章来源地址https://www.toymoban.com/news/detail-734160.html

到了这里,关于【C#进阶】C# 事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 每个.NET开发都应掌握的C#集合知识点

    上篇文章讲述了C#委托和事件知识点,本文将介绍C#集合知识点。作为.NET开发人员,C#集合是你在构建强大和高效应用程序时的关键技能之一。C#集合提供了一系列丰富的数据结构,可以帮助你更好地管理、操作和组织数据。本文将介绍一些每个.NET开发人员都应该掌握的C#集合

    2024年02月10日
    浏览(47)
  • 每个.NET开发都应掌握的C#接口知识点

    作为.NET开发者,接口是C#必须掌握的知识点,接口是C#中实现多态和组件间互操作性的关键机制之一。 接口是一种抽象的类型,它定义了一组成员(方法、属性、事件等)的规范,但没有实现代码。类可以实现一个或多个接口,以表明它们提供了特定的功能。 以下是每个.N

    2024年02月13日
    浏览(46)
  • 【《C# 10 和 .NET 6入门与跨平台开发(第6版)》——一本循序渐进的C#指南】

    这个新版本对上一版做了全面修订,涵盖C# 10和.NET 6的所有新功能. 本书讨论面向对象编程、编写函数、测试函数、调试函数、实现接口以及继承类等主题;介绍.NET API,这些API可执行多种任务,如管理和查询数据,监视和改进性能,以及使用文件系统、异步流、序列化和加密

    2024年02月14日
    浏览(44)
  • 每个.NET开发都应掌握的C#多线程知识点

    上篇文章讲述了C#特性(Attribute)知识点,本文将介绍多线程的知识点。多线程编程是现代软件开发中的重要组成部分,它能够充分利用多核处理器,提高应用程序的性能和响应性。C#作为.NET开发的主要语言,提供了强大的多线程支持。本文将介绍C#多线程知识点,帮助.NET开

    2024年02月05日
    浏览(60)
  • 每个.NET开发都应掌握的C#异常处理知识点

    上篇文章讲述了C#集合知识点,本文将介绍C#异常处理知识点。异常处理是.NET开发中至关重要的一部分,它允许开发者在程序出现错误或不正常情况时采取适当的措施,从而提高应用程序的稳定性和可靠性。本文将介绍C#异常处理知识点,异常的基本概念略过,请查看官网。

    2024年02月08日
    浏览(54)
  • 每个.NET开发都应掌握C#泛型的知识点

    C#泛型编程是.NET framework 2.0的新特征,它提高了代码安全性和代码重用的问题。由于泛型必须指定类型,正确的使用可以避免了装箱拆箱的问题;使用了泛型后,可以将算法或组件泛型化,基于类型参数支持任意数据类型,从而提高了代码的重用性。 C#泛型编程在C#是很重要的特

    2024年02月15日
    浏览(46)
  • 每个.NET开发都应掌握的C#特性(Attribute)知识点

    上篇文章讲述了C#反射知识点,本文将介绍C#特性(Attribute)的知识点。C#特性(Attribute)是一种强大的元数据机制,用于为代码元素(如类、方法、属性等)添加信息,以影响它们的行为或提供额外的信息。本文将介绍C#特性每个.NET开发都应熟悉的知识点,希望对大家开发有

    2024年02月08日
    浏览(41)
  • 【Unity 踩坑系列】配置VScode的C#环境自动下载 .NET Runtime Failed to download 问题解决后续!!!

    想必大家这几天肯定都被Vscode C#插件的自动下载.net runtime的问题所烦恼,之前我也出了一期文章是来解决这个问题的但是,只是解决了部分网友们的问题有部分网友还是会自动下载! 【Unity 踩坑系列】配置VScode环境Downloading the.NET Runtime Failed to download 之前没看过这篇解决方案

    2024年02月10日
    浏览(41)
  • 每个.NET开发都应掌握的C#处理文件系统I/O知识点

    上篇文章讲述了C#多线程知识点,本文将介绍C#处理文件的知识点。在.NET开发领域,文件系统I/O是一个至关重要的主题,尤其是在处理文件、目录和数据存储方面。C#作为.NET平台的主要编程语言,提供了丰富而强大的文件系统I/O功能,为开发人员提供了灵活的工具,使其能够

    2024年02月05日
    浏览(43)
  • 【C#进阶】C# 事件

    序号 系列文章 15 【C#进阶】C# 属性 16 【C#进阶】C# 索引器 17 【C#进阶】C# 委托 🌍 hello大家好啊,我是哈桑。本文为大家介绍 C# 中的事件。 事件 本质上来讲是一种特殊的多播委托 1 ,只能从声明它的类中进行调用。事件通常用于表示用户操作,例如单击按钮或图形用户界面

    2024年02月07日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包