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

news2024/11/15 8:21:37

文章目录

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

在这里插入图片描述


在面向对象编程中,继承是代码复用的一种重要方式。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 publisher
	public 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 subscribers
		ShapeChanged?.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 subscriber
	var 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
*/
}

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2067769.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【UE】尝试一种老派的平面假反射做法,与进一步改进效果的思路

在实践中&#xff0c;常常需要为类似荧幕&#xff0c;LED广告牌等平面制作反射。 但会遇到各种问题&#xff0c;例如在使用屏幕空间反射时&#xff0c;平面必须在画面内 平面反射捕获与光线追踪又代价高昂 因此&#xff0c;在一些情况下依然会使用一种历史悠久的反射手法 这种…

树(二叉树)

树 1.1 特性 1.1.1 什么是树 树(Tree)是(n>0)个节点的有限集合T&#xff0c;它满足两个条件&#xff1a; (1) 有且仅有一个特定的称为根&#xff08;Root&#xff09;的节点。 其余的节点可以分为m&#xff08;m≥0&#xff09;个互不相交的有限集合T1、T2、……、Tm&#x…

【Docker】Linux系统以及威联通QNAP部署思源笔记的通用教程

本文首发于 ❄️慕雪的寒舍 本文测试的是旧版本v2.11.4的部署方式&#xff0c;实测当前&#xff08;2024.08.15&#xff09;最新的v3.1.3版本也可以用相同的方式部署。本文的部署方式共写了三种&#xff0c;非qnap的linux系统也可以参考本文部署思源笔记。 阅读本文之前&#…

SpringBoot 集成积木报表

SpringBoot 集成积 前言 积木报表是jeecg的一款开源但代码不开源的一款自定义报表&#xff0c;可以基于网页灵活 调整报表的布局、样式等内容&#xff0c;无需编程&#xff0c;专为企业数据分析、报表制作而设计&#xff1b; 降低管理人员汇总制作报表的门槛&#xff0c;解决…

在表格上,按照单元格数值显示单元格背景进度条

想要实现的效果如下&#xff1a; 单元格背景进度条的大小取决于当前单元格里的数值 TreeList和GridControl的设置方法都是相同的&#xff1a;都是通过给列设置FormatRule来实现的。 相关代码及设置如下&#xff1a; 1、给控件绑定数据源&#xff0c;我的数据源是一个DataTab…

25届网安秋招,信息泄露常问之配置信息泄露

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247485367&idx1&sn837891059c360ad60db7e9ac980a3321&chksmc0e47eebf793f7fdb8fcd7eed8ce29160cf79ba303b59858ba3a6660c6dac536774afb2a6330#rd 《网安面试指南》http://mp.weixin.qq.com/s?…

基于STM32开发的智能花园灌溉系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化土壤湿度监测与处理灌溉控制与状态指示Wi-Fi通信与远程监控应用场景 家庭花园智能灌溉农业田地的智能灌溉管理常见问题及解决方案 常见问题解决方案结论 1. 引言 随着智能家居技术…

录屏神器!一键搞定视频录制,小白也能轻松上手

在工作当中录制会议内容或者看电影录制精彩瞬间、学习时录制网课的重点部分等等都是需要借助可以实现屏幕录制的工具&#xff0c;让我们的日常更加精彩并且有回忆的记录&#xff0c;今天就来给大家整理了四款好用的录屏工具&#xff0c;实现保存高清、流畅的电脑屏幕的精彩记录…

重定向

重定向原理 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> int main() { close(1); int fd open("myfile", O_WRONLY|O_CREAT, 00644); if(fd < 0){ perror("o…

V-ASSISTANT软件无法设置V90伺服软限位

使用V-ASSISTANT软件配置V90伺服参数时&#xff0c;软限位功能是灰色且未勾选&#xff0c;无法设置软限位&#xff0c;如下图所示&#xff1a; 原因&#xff1a;设置零点位置之后需要在PLC中激活软限位&#xff08;如FB284中ConfigEPOS管脚的Bit2&#xff09; FB284中的Confi…

python学习之路 - pyecharts快速入门

目录 一、pyecharts入门1、pyecharts模块介绍a、概况 2、pyecharts基础入门&#xff08;以折线图为例&#xff09;a、安装依赖b、创建折线图c、常用配置项 3、pyecharts创建柱状图a、创建基本柱状图b、创建反转柱状图c、创建含有时间线的柱状图 4、pyecharts地图可视化a、生成中…

WSL-ubuntu下载安装配置cudnn

下载 安装cuDnn的话需要和CUDA版本对应&#xff0c;可参考官网&#xff1a; cuDNN Archive | NVIDIA Developer 我的cuda是11.8 这个cuDNN8.9.7_Linux直接下载&#xff1a; https://developer.nvidia.com/downloads/compute/cudnn/secure/8.9.7/local_installers/11.x/cudn…

无人机技术的最新进展及未来趋势

一、飞行控制技术的提升 复杂环境下的稳定性&#xff1a;现代无人机在飞行控制系统方面的升级&#xff0c;使其能在复杂环境中稳定飞行&#xff0c;例如强风条件下或狭窄空间内。 智能避障系统&#xff1a;新型无人机配备有高精度的传感器和先进的算法&#xff0c;能够实现自…

vue3快速入门(一)新建项目与安装插件

步骤很详细&#xff0c;直接上教程 在对应路径下&#xff0c;cmd输入npm create vuelatest,然后按图所示进行选择&#xff08;仅供新手参考&#xff09; 安装以下插件 3.重启vscode&#xff08;为了确保插件生效&#xff09; 4.在vscode启动内置终端 输入npm i或pnpm i安装依赖…

浅谈 mysql 单、双引号的3种用法

mysql 单引号和双引号的使用&#xff0c;主要有以下3种情形 1、在引用字符型或日期类型的值时使用。 2、使用 as 创建别名时使用&#xff0c;别名如含特殊字符&#xff0c;则必须使用单引号或双引号。 3、解决数据原文中存在的单双引号问题。 注&#xff1a;本文所指的单、…

【Docker】Docker学习01 | 什么是docker?

本文首发于 ❄️慕雪的寒舍 因为本人没有学习过docker&#xff0c;虽然部署过很多镜像&#xff0c;但是对于docker底层的实现一概不知。趁学习一个新项目的契机&#xff0c;将docker的相关概念了解清楚。 安装docker的教程请查看 Linux主机安装docker。 如果你想和我一起学习do…

内存管理篇-02内存硬件电路和接口

1. 内存硬件实现机制 通过D触发器构建寄存器和内存的结构对比,这里主要先表达sram复杂&#xff0c;dram简单。 2. sram和ddr sdram结构图对比 主要是想对比sram和dram在和CPU连接过程的差异。sram需要的地址线较多&#xff0c;dram需要的较少&#xff0c;但是需要多次发送&…

如何用Python进行民宿数据分析?可视化工具应用教程

&#x1f393; 作者&#xff1a;计算机毕设小月哥 | 软件开发专家 &#x1f5a5;️ 简介&#xff1a;8年计算机软件程序开发经验。精通Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等技术栈。 &#x1f6e0;️ 专业服务 &#x1f6e0;️ 需求定制化开发源码提…

微信小游戏授权问题

微信小程序获取用户相关信息的接口&#xff0c;如wx.getUserCloudStorage&#xff0c;报错&#xff1a;please go to mp to announce your privacy usage。 需要在微信公众平台设置用户隐私保护。

CentoOS 7下配置并部署 DataX 3.0与DataX-web

数据同步框架 DataX DataX本身作为离线数据同步框架,采用 Framework plugin架构构建。将数据源读取和写入抽象成为Reader/ Writer插件,纳入到整个同步框架中。 Reader: Reader为数据采集模块,负责采集数据源的数据,将数据发送给 Framework。 Writer: Writer为数据写入模块,负责…