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

相关文章

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

springboot security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

golang 日志log与logrus示例详解

《golang日志log与logrus示例详解》log是Go语言标准库中一个简单的日志库,本文给大家介绍golang日志log与logrus示例详解,感兴趣的朋友一起看看吧... 目录一、Go 标准库 log 详解1. 功能特点2. 常用函数3. 示例代码4. 优势和局限二、第三方库 logrus 详解1.

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

C#基础之委托详解(Delegate)

《C#基础之委托详解(Delegate)》:本文主要介绍C#基础之委托(Delegate),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 委托定义2. 委托实例化3. 多播委托(Multicast Delegates)4. 委托的用途事件处理回调函数LINQ