C#下在派生类中引发基类事件的方法与示例

2024-08-23 23:28

本文主要是介绍C#下在派生类中引发基类事件的方法与示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 基类事件在派生类中的定义及触发方式
    • 基类事件的传播机制
    • 示例
    • 总结

在这里插入图片描述


在面向对象编程中,继承是代码复用的一种重要方式。C#作为一种面向对象的编程语言,允许派生类继承基类的属性和方法。基类定义了一系列共有的属性和行为,而派生类则可以在基类的基础上添加新的特性或重写基类的方法。事件作为一种特殊的成员,也可以在基类中被定义,并在派生类中被触发和使用。

基类事件在派生类中的定义及触发方式

在C#中,事件是一种使类或对象可以通知其他类或对象发生了某些事情的一种机制。在基类中定义事件,然后在派生类中触发这些事件是常见的做法。下面是一个简单的基类事件定义的例子:

public class BaseClass
{// 定义一个事件public event EventHandler MyEvent;// 触发事件的保护方法protected virtual void OnMyEvent(EventArgs e){MyEvent?.Invoke(this, e);}
}

在派生类中,我们可以通过调用基类中定义的保护方法来触发事件:

public class DerivedClass : BaseClass
{// 触发基类事件的派生类方法public void TriggerEvent(){OnMyEvent(EventArgs.Empty);}
}

基类事件的传播机制

基类事件的传播机制主要有两种:主动传播和自动传播。

主动传播
主动传播是指派生类明确调用基类的事件触发方法。这种方式要求派生类知道基类的事件触发方法,并显式调用它。如上例所示,TriggerEvent 方法调用了 OnMyEvent 方法。

自动传播
自动传播是指派生类重写基类的方法,并在其中触发基类事件。这样,当基类的方法被调用时,事件也会被自动触发。例如:

public class BaseClass
{public event EventHandler MyEvent;protected virtual void OnMyEvent(EventArgs e){MyEvent?.Invoke(this, e);}public virtual void DoSomething(){// 基类方法逻辑}
}public class DerivedClass : BaseClass
{public override void DoSomething(){// 派生类自己的逻辑base.DoSomething(); // 调用基类方法OnMyEvent(EventArgs.Empty); // 触发事件}
}

示例

下面是一个完整的示例,展示了基类事件如何在派生类中被触发:

using System;public class BaseClass
{public event EventHandler MyEvent;protected virtual void OnMyEvent(EventArgs e){MyEvent?.Invoke(this, e);}public void TriggerBaseEvent(){OnMyEvent(EventArgs.Empty);}
}public class DerivedClass : BaseClass
{public void DoSomething(){Console.WriteLine("DerivedClass is doing something.");OnMyEvent(EventArgs.Empty); // 触发基类事件}
}class Program
{static void Main(){DerivedClass derived = new DerivedClass();derived.MyEvent += (sender, e) => Console.WriteLine("Event triggered from DerivedClass.");derived.DoSomething(); // 触发事件derived.TriggerBaseEvent(); // 直接触发基类的事件}
}

在这个示例中,我们创建了一个派生类 DerivedClass,它继承自 BaseClass 并重写了 DoSomething 方法。在这个方法中,我们调用了 OnMyEvent 方法来触发基类的事件。

完整示例

namespace BaseClassEvents
{// Special EventArgs class to hold info about Shapes.public class ShapeEventArgs : EventArgs{public ShapeEventArgs(double area){NewArea = area;}public double NewArea { get; }}// Base class event publisherpublic abstract class Shape{protected double _area;public double Area{get => _area;set => _area = value;}// The event. Note that by using the generic EventHandler<T> event type// we do not need to declare a separate delegate type.public event EventHandler<ShapeEventArgs> ShapeChanged;public abstract void Draw();//The event-invoking method that derived classes can override.protected virtual void OnShapeChanged(ShapeEventArgs e){// Safely raise the event for all subscribersShapeChanged?.Invoke(this, e);}}public class Circle : Shape{private double _radius;public Circle(double radius){_radius = radius;_area = 3.14 * _radius * _radius;}public void Update(double d){_radius = d;_area = 3.14 * _radius * _radius;OnShapeChanged(new ShapeEventArgs(_area));}protected override void OnShapeChanged(ShapeEventArgs e){// Do any circle-specific processing here.// Call the base class event invocation method.base.OnShapeChanged(e);}public override void Draw(){Console.WriteLine("Drawing a circle");}}public class Rectangle : Shape{private double _length;private double _width;public Rectangle(double length, double width){_length = length;_width = width;_area = _length * _width;}public void Update(double length, double width){_length = length;_width = width;_area = _length * _width;OnShapeChanged(new ShapeEventArgs(_area));}protected override void OnShapeChanged(ShapeEventArgs e){// Do any rectangle-specific processing here.// Call the base class event invocation method.base.OnShapeChanged(e);}public override void Draw(){Console.WriteLine("Drawing a rectangle");}}// Represents the surface on which the shapes are drawn// Subscribes to shape events so that it knows// when to redraw a shape.public class ShapeContainer{private readonly List<Shape> _list;public ShapeContainer(){_list = new List<Shape>();}public void AddShape(Shape shape){_list.Add(shape);// Subscribe to the base class event.shape.ShapeChanged += HandleShapeChanged;}// ...Other methods to draw, resize, etc.private void HandleShapeChanged(object sender, ShapeEventArgs e){if (sender is Shape shape){// Diagnostic message for demonstration purposes.Console.WriteLine($"Received event. Shape area is now {e.NewArea}");// Redraw the shape here.shape.Draw();}}
}
class Test
{
static void Main()
{//Create the event publishers and subscribervar circle = new Circle(54);var rectangle = new Rectangle(12, 9);var container = new ShapeContainer();// Add the shapes to the container.container.AddShape(circle);container.AddShape(rectangle);// Cause some events to be raised.circle.Update(57);rectangle.Update(7, 7);// Keep the console window open in debug mode.Console.WriteLine("Press any key to continue...");Console.ReadKey();
}
}/* Output:
Received event. Shape area is now 10201.86
Drawing a circle
Received event. Shape area is now 49
Drawing a rectangle
*/
}

总结

在派生类中引发基类事件可以增强代码的可重用性、封装性和灵活性。通过这种方式,我们可以确保基类的行为能够在派生类中得到正确的通知,而无需在每个派生类中重新定义事件。这不仅减少了代码的冗余,还使得基类和派生类之间的交互更加清晰和一致。通过合理地使用事件,我们可以构建出更加健壮和易于维护的面向对象系统。

这篇关于C#下在派生类中引发基类事件的方法与示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1100798

相关文章

Python常用命令提示符使用方法详解

《Python常用命令提示符使用方法详解》在学习python的过程中,我们需要用到命令提示符(CMD)进行环境的配置,:本文主要介绍Python常用命令提示符使用方法的相关资料,文中通过代码介绍的... 目录一、python环境基础命令【Windows】1、检查Python是否安装2、 查看Python的安

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

LiteFlow轻量级工作流引擎使用示例详解

《LiteFlow轻量级工作流引擎使用示例详解》:本文主要介绍LiteFlow是一个灵活、简洁且轻量的工作流引擎,适合用于中小型项目和微服务架构中的流程编排,本文给大家介绍LiteFlow轻量级工... 目录1. LiteFlow 主要特点2. 工作流定义方式3. LiteFlow 流程示例4. LiteF

Maven 配置中的 <mirror>绕过 HTTP 阻断机制的方法

《Maven配置中的<mirror>绕过HTTP阻断机制的方法》:本文主要介绍Maven配置中的<mirror>绕过HTTP阻断机制的方法,本文给大家分享问题原因及解决方案,感兴趣的朋友一... 目录一、问题场景:升级 Maven 后构建失败二、解决方案:通过 <mirror> 配置覆盖默认行为1. 配置示

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

Java中Map.Entry()含义及方法使用代码

《Java中Map.Entry()含义及方法使用代码》:本文主要介绍Java中Map.Entry()含义及方法使用的相关资料,Map.Entry是Java中Map的静态内部接口,用于表示键值对,其... 目录前言 Map.Entry作用核心方法常见使用场景1. 遍历 Map 的所有键值对2. 直接修改 Ma

MyBatis ResultMap 的基本用法示例详解

《MyBatisResultMap的基本用法示例详解》在MyBatis中,resultMap用于定义数据库查询结果到Java对象属性的映射关系,本文给大家介绍MyBatisResultMap的基本... 目录MyBATis 中的 resultMap1. resultMap 的基本语法2. 简单的 resul

Mybatis Plus Join使用方法示例详解

《MybatisPlusJoin使用方法示例详解》:本文主要介绍MybatisPlusJoin使用方法示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录1、pom文件2、yaml配置文件3、分页插件4、示例代码:5、测试代码6、和PageHelper结合6