C#中抽象类、抽象方法和接口暨内联临时变量的精彩表达

目录

一、抽象类

 1.示例

二、抽象方法

三、接口

1.示例

2.内联表达治愈警告CA1859

(1)传统程序书写源码

(2)内联后的源码

四、多重继承

1.示例

五、显式接口成员实现

1.示例

六、总结 


赠人玫瑰,手有余香, 留下心得,换点流量。

一、抽象类

        一般将父类定义为抽象类,需要使用这个父类进行继承与多态处理。C#中声明抽象类时需要使用abstract关键字,声明抽象类时,除abstract关键字、class关键字和类名外,其他的都是可选项。

        抽象类除了被继承之外没有任何意义

 1.示例

//抽象类、抽象方法
namespace _01
{public abstract class MyClass{private string id = "";private string name = "";/// <summary>/// 编号属性及实现/// </summary>public string ID{get{return id;}set{id = value;}}/// <summary>/// 姓名属性及实现/// </summary>public string Name{get{return name;}set{name = value;}}/// <summary>/// 抽象方法,用来输出信息/// </summary>public abstract void ShowInfo();}public class DriveClass : MyClass			     //继承抽象类{/// <summary>/// 重写抽象类中输出信息的方法/// </summary>public override void ShowInfo(){Console.WriteLine(ID + " " + Name);}}class Program{/// <summary>/// 内联/// </summary>static void Main(string[] args){DriveClass driveclass = new();     //实例化派生类,内联前用派生类对象实例化抽象类                                                             ((DriveClass)driveclass).ID = "BH0001"; //使用抽象类对象访问抽象类中的编号属性((DriveClass)driveclass).Name = "TM";   //使用抽象类对象访问抽象类中的姓名属性((DriveClass)driveclass).ShowInfo();    //使用抽象类对象调用派生类中的方法Console.WriteLine("------------");driveclass.ID = "BH0001";              //派生类直接实例化driveclass.Name = "TM";driveclass.ShowInfo();Console.Read();}}
}//结果:
/*BH0001 TM
---------------
BH0001 TM*/

二、抽象方法

        在抽象类中声明方法时,如果加上abstract关键字,则为抽象方法。

        使用abstract关键字定义的类称为抽象类,而使用这个关键字定义的方法称为抽象方法,抽象方法没有方法体,这个方法本身没有任何意义,除非它被重写,而承载这个抽象方法的抽象类就必须被继承。反之,如果声明一个抽象的方法,就必须将承载这个抽象方法的类定义为抽象类,不可能在非抽象类中获取抽象方法。只要类中有一个抽象方法,此类就被标记为抽象类。

        抽象类被继承后需要实现其中所有的抽象方法,也就是保证相同的方法名称、参数列表和相同返回值类型创建出非抽象方法,当然也可以是抽象方法。继承抽象类的所有子类需要将抽象类中的抽象方法进行覆盖。

声明抽象方法时需要注意以下两点:
☑ 抽象方法必须声明在抽象类中。
☑ 声明抽象方法时,不能使用virtual、static和private修饰符。

        抽象方法声明引入了一个新方法,但不提供该方法的实现,由于抽象方法不提供任何实际实现,因此抽象方法的方法体只包含一个分号。

        当从抽象类派生一个非抽象类时,需要在非抽象类中重写抽象方法,以提供具体的实现,重写抽象方法时使用override关键字。

三、接口

        接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。接口可由方法、属性、事件和索引器或这4种成员类型的任何组合构成,但不能包含字段,也不能设置这些成员的具体值,即,只能定义,不能给它们赋值。 接口可以继承其他接口。  

接口具有以下特征:
☑ 接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。
☑ 不能直接实例化接口。
☑ 接口可以包含事件、索引器、方法和属性。
☑ 接口不包含方法的实现。
☑ 类和结构可从多个接口继承。
☑ 接口自身可从多个接口继承。

1.示例

// 接口
namespace _02
{interface IMyInterface{/// <summary>/// 编号(可读可写)/// </summary>string ID{get;set;}/// <summary>/// 姓名(可读可写)/// </summary>string Name{get;set;}/// <summary>/// 显示定义的编号和姓名/// </summary>void ShowInfo();}class Program : IMyInterface    //继承自接口{string id = "";string name = "";/// <summary>/// 编号/// </summary>public string ID{get{return id;}set{id = value;}}/// <summary>/// 姓名/// </summary>public string Name{get{return name;}set{name = value;}}/// <summary>/// 显示定义的编号和姓名/// </summary>public void ShowInfo(){Console.WriteLine("编号\t 姓名");Console.WriteLine(ID + "\t " + Name);}/// <summary>/// 注释掉的部分,警告CA1859/// 内联临时变量后,警告消失/// </summary>static void Main(string[] args){Program program = new();                      //实例化Program类对象//IMyInterface Imyinterface = program;        //使用派生类对象实例化接口ImyInterface//Imyinterface.ID = "TM";                     //为派生类中的ID属性赋值//Imyinterface.Name = "C#从入门到精通";        //为派生类中的Name属性赋值//Imyinterface.ShowInfo();((IMyInterface)program).ID = "TM";            //为派生类中的ID属性赋值((IMyInterface)program).Name = "C#从入门到精通";//为派生类中的Name属性赋值((IMyInterface)program).ShowInfo();            //调用派生类中方法显示定义的属性值Console.WriteLine("----------------------");   //用子类派生类直接实例化program.ID = "TM";program.Name = "C#从入门到精通";program.ShowInfo();Console.Read();}}
}//运行结果:
/*
编号     姓名
TM       C#从入门到精通
----------------------
编号     姓名
TM       C#从入门到精通*/

2.内联表达治愈警告CA1859

         上述示例中,传统的Main()方法中,先实例化派生类Program,再用派生对象实例化接口,然后用接口的属性为派生类属性赋值。这是.NET Framework 4.8之前的做法,其缺点是程序表达晦涩,不易读,继承关系不明显。

        在.NET 7.0、.NET 8.0下不建议这样表达,会提示警告CA1859。VS2022.NET 8.0快速重构建议给出的意见是用内联临时变量的方法,直接表达继承关系,使得程序简洁易读,继承关系清晰明了。

严重性

代码

说明

项目

文件

禁止显示状态

消息

CA1859

将变量“_Imyinterface”的类型从“_02.IMyInterface”更改为“_02.Program”,以提高性能

02

E:\C#_TM\chapter17\02\Program.cs

72

活动

(1)传统程序书写源码

static void Main(string[] args)
{Program program = new();				//实例化Program类对象IMyInterface Imyinterface = program;    //使用派生类对象实例化接口ImyInterfaceImyinterface.ID = "TM";                 //为派生类中的ID属性赋值Imyinterface.Name = "C#从入门到精通";    //为派生类中的Name属性赋值Imyinterface.ShowInfo();				//调用派生类中方法显示定义的属性值Console.WriteLine("------------------");//用子类派生类直接实例化program.ID = "TM";program.Name = "C#从入门到精通";program.ShowInfo();Console.Read();
}

(2)内联后的源码

static void Main(string[] args){Program program = new();                         //实例化Program类对象//使用派生类对象实例化接口     	                 ((IMyInterface)program).ID = "TM";               //为派生类中的ID属性赋值((IMyInterface)program).Name = "C#从入门到精通";  //为派生类中的Name属性赋值((IMyInterface)program).ShowInfo();              //调用派生类中方法显示定义的属性值Console.WriteLine("----------------------");	  //用子类派生类直接实例化program.ID = "TM";program.Name = "C#从入门到精通";program.ShowInfo();Console.Read();}

        内联的表达可以隐藏(舍去)   ,结果是一样的,只是继承关系不再明显可见了。     

        后面的例子中都会出现CA1859警告,其处理方法同此例,不再重复讲述。

四、多重继承

        可以只继承一个接口,接口也可以多重继承,使用多重继承时,要继承的接口之间用逗号“,”分隔。

1.示例

// 继承多个接口
namespace _03
{interface IPeople{/// <summary>/// 姓名/// </summary>string Name{get;set;}/// <summary>/// 性别/// </summary>string Sex{get;set;}}interface ITeacher : IPeople            //继承公共接口{/// <summary>/// 教学方法/// </summary>void Teach();}interface IStudent : IPeople            //继承公共接口{/// <summary>/// 学习方法/// </summary>void Study();}class Program : IPeople, ITeacher, IStudent//多接口继承{string name = "";string sex = "";/// <summary>/// 姓名/// </summary>public string Name{get{return name;}set{name = value;}}/// <summary>/// 性别/// </summary>public string Sex{get{return sex;}set{sex = value;}}/// <summary>/// 教学方法/// </summary>public void Teach(){Console.WriteLine(Name + " " + Sex + " 教师");}/// <summary>/// 学习方法,学习内联的表达/// 内联前,用派生类对象实例化接口ITeacher/// 内联前,用派生类对象实例化接口IStudent/// 舍去内联的表达后效果一样,内联的存在使得继承关系清晰明了/// </summary>public void Study(){Console.WriteLine(Name + " " + Sex + " 学生");}static void Main(string[] args){Program program = new();   //实例化类对象,内联表达((ITeacher)program).Name = "TM";((ITeacher)program).Sex = "男";((ITeacher)program).Teach();((IStudent)program).Name = "C#";((IStudent)program).Sex = "男";((IStudent)program).Study();Console.WriteLine("--舍去内联--");program.Name = "TM";program.Sex = "男";program.Teach();program.Name = "C#";program.Sex = "男";program.Study();Console.Read();}}
}//运行结果:
/*
TM 男 教师
C# 男 学生
--舍去内联--
TM 男 教师
C# 男 学生     */

五、显式接口成员实现

        如果类实现两个接口,并且这两个接口包含具有相同签名的成员,那么在类中实现该成员将导致两个接口都使用该成员作为它们的实现。然而,如果两个接口成员实现不同的功能,则可能会导致其中一个接口的实现不正确或两个接口的实现都不正确,这时可以显式地实现接口成员,即创建一个仅通过该接口调用并且特定于该接口的类成员。显式接口成员实现是使用接口名称和一个句点命名该类成员来实现的。

        显式接口成员实现中不能包含访问修饰符、abstract、virtual、override或static修饰符。

        显式接口成员属于接口的成员,而不是类的成员,因此,不能使用类对象直接访问,只能通过接口对象来访问。

         使用场合:当继承多个接口的类中欲实现来自各自接口的同名方法赋予不同的功能时。

1.示例

// 显式接口成员实现
namespace _04
{interface IMyInterface1{/// <summary>/// 求和方法/// </summary>int Add();}interface IMyInterface2{/// <summary>/// 求和方法/// </summary>int Add();}/// <summary>/// 显式接口成员实现/// </summary>class MyClass : IMyInterface1, IMyInterface2    //继承接口{/// <summary>/// 求和方法1/// </summary>int IMyInterface1.Add()					    //显式接口成员实现{int x = 3;int y = 5;return (x + y);}/// <summary>/// 求和方法2/// </summary>int IMyInterface2.Add()					    //显式接口成员实现{int x = 3;int y = 5;int z = 7;return (x + y + z);}}class Program{static void Main(string[] args){MyClass myclass = new();			        //实例化接口继承类的对象IMyInterface1 imyinterface1 = myclass;		//使用接口继承类的对象实例化接口Console.WriteLine(imyinterface1.Add());		//使用接口对象调用接口中的方法IMyInterface2 imyinterface2 = myclass;		//使用接口继承类的对象实例化接口Console.WriteLine(imyinterface2.Add());		//使用接口对象调用接口中的方法Console.WriteLine("----内联表达----");       //使用内联表达,是不是更清晰易读?Console.WriteLine(((IMyInterface1)myclass).Add());  Console.WriteLine(((IMyInterface2)myclass).Add());Console.Read();}}
}//运行结果:
/*
8
15
----内联表达----
8
15      */

        内联表达,用最少的语句,实现最清晰的继承关系表达,是不是你的最爱?

六、总结 

        抽象类和接口都包含可以由派生类继承的成员,它们都不能直接实例化,但可以声明它们的变量。如果这样做,就可以使用多态性把继承这两种类型的对象指定给它们的变量。

        抽象类和接口这两种类型用于完全不同的目的。抽象类主要用作对象系列的基类,共享某些主要特性,例如共同的目的和结构。接口则主要用于类,这些类在基础水平上有所不同,但仍可以完成某些相同的任务。

抽象类和接口的区别主要有以下几点: 
☑ 它们的派生类只能继承一个基类,即只能直接继承一个抽象类,但可以继承任意多个接口。 
☑ 抽象类中可以定义成员的实现,但接口中不可以。 
☑ 抽象类中可以包含字段、构造函数、析构函数、静态成员或常量等,接口中不可以。 
☑ 抽象类中的成员可以是私有的(只要它们不是抽象的)、受保护的、内部的或受保护的内部成员(受保护的内部成员只能在应用程序的代码或派生类中访问),但接口中的成员必须是公共的。
☑ 派生类必须继承抽象类的全部。派生类可以选择是否继承接口。
☑ 抽象类使得所有派生类大同小异,继承多个接口则使得派生类各有不同。

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

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

相关文章

梅见们要靠“年轻化”突围,但代理商们面对新酒饮还需冷静

文 | 螳螂观察&#xff08;TanglangFin&#xff09; 作者 | kinki 沉寂了三年之后&#xff0c;今年酒行业再度热闹了起来&#xff0c;大大小小的展会接连落地&#xff0c;各大酒企都在忙着探索新模式、处理客情、选品招商……想要将过去三年的业绩追回来。 对于酒行业的代理…

MySQL数据库面试题总结(2022最新版)

&#x1f436; 程序猿周周 ⌨️ 短视频小厂BUG攻城狮 &#x1f93a; 如果文章对你有帮助&#xff0c;记得关注、点赞、收藏&#xff0c;一键三连哦&#xff0c;你的支持将成为我最大的动力 本文是《后端面试小册子》系列的第 1️⃣ 篇文章&#xff0c;该系列将整理和梳理笔者作…

EasyExcel 注解fillForegroundColor

EasyExcel 注解fillForegroundColor 对应的颜色值 /** * 样式的数据类 * * author leiyiDong **/ Data // 头背景设置成红色 IndexedColors.RED.getIndex() HeadStyle(fillPatternType FillPatternType.SOLID_FOREGROUND, fillForegroundColor 10) // 头字体设置成20 Hea…

大数据Doris(二十八):Routine Load查看和修改作业

文章目录 Routine Load查看和修改作业 一、​​​​​​​查看导入作业状态

Audition 2024 24.0.0.46(音频剪辑)

Audition 2024是一款非常棒的音频编辑和混合软件&#xff0c;提供了广泛的工具和功能&#xff0c;用于创建、编辑、混合和设计音效。这款软件旨在加速音频和视频制作工作流程&#xff0c;提供具有原始音效的高质量混音。其界面构成清晰&#xff0c;操作简便&#xff0c;适合专业…

Linux下载工具XDM下载安装与使用

Windows上IDM多线程下载非常强大&#xff0c;即能捕捉页面上的视频、图片、音频&#xff0c;又能作为浏览器下载器使用&#xff0c;但是IDM无法在Linux下使用&#xff0c;除非使用wine。不过我们可以在Linux中用XDM(Xtreme Download Manager)代替IDM。 1、XDM下载 Xtreme Dow…

Java的ArrayList中关于删除的常用操作及方法

目录 remove(int index)方法 remove(Object o)方法 removeAll​(Collection c)方法 removeIf​(Predicate filter)方法 removeRange​(int fromIndex, int toIndex)方法 remove(int index)方法 remove(int index)是ArrayList类中用于删除指定位置元素的方法。它接收一个整…

小程序Canvas 2D问题解决,如安卓drawImage不执行、动态高度设置、高度1365(或4096)限制等

我的最新版小程序想在绘制时使用自定义字体&#xff0c;需要将旧版canvas升级到2d新版&#xff0c;发现了许多问题&#xff0c;下面记录一下并提供解决思路&#xff0c;仅供参考&#xff0c;欢迎提供新思路。 一、开发工具和安卓上drawImage不执行&#xff0c;绘制出来是空白&…

聊聊tomcat的connection-timeout

序 本文主要研究一下tomcat的connection-timeout ServerProperties.Tomcat org/springframework/boot/autoconfigure/web/ServerProperties.java public static class Tomcat {/*** Access log configuration.*/private final Accesslog accesslog new Accesslog();/*** Th…

github批量仓库克隆,git clone某个用户的所有仓库

利用github的api工具&#xff0c; 首先拿到用户名为kevin的所有仓库的url&#xff1a; curl "https://api.github.com/users/kevin/repos?per_page100&&page1" | grep -w clone_url >clone.txt过滤一下&#xff1a; grep -o https://[^"]* clone…

DM8单点_闪回查询报错flashback version has been out of date

问题描述 误操作后&#xff0c;闪回查询到某一时间点提示:“[-9801]:flashback version has been out of date.” SQL> SELECT * FROM PERSON_TYPE WHEN TIMESTAMP 2023-11-23 18:51:41; SELECT * FROM PERSON_TYPE WHEN TIMESTAMP 2023-11-23 18:51:41; [-9801]:flashbac…

redis运维(十九)redis 的扩展应用 lua(一)

一 redis 的扩展应用 lua redis如何保证原子操作 说明&#xff1a;引入lua脚本,核心解决原子性问题 ① redis为什么引入lua? lua脚本本身体积小,启动速度快 ② redis引入lua的优势 小结&#xff1a; 类似自定义redis命令 ③ redis中如何使用lua ④ EVAL 说明&#…

性能测试的指南:测试类型、性能测试步骤、最佳实践等!

近期公司为了节省成本搞了一波机房迁移&#xff0c;整合了一些南美部署架构。有一些上google云和有些下阿里云等大的调整。 在做机房迁移项目当中就需要思考如何进行性能测试&#xff0c;这种大的机房迁移SRE&#xff08;运维&#xff09;会针对组件会做一些单组件的性能测试&a…

【深度学习】参数优化和训练技巧

寻找合适的学习率(learning rate) 学习率是一个非常非常重要的超参数&#xff0c;这个参数呢&#xff0c;面对不同规模、不同batch-size、不同优化方式、不同数据集&#xff0c;其最合适的值都是不确定的&#xff0c;我们无法光凭经验来准确地确定lr的值&#xff0c;我们唯一可…

6.2.SDP协议

那今天呢&#xff1f;我们来介绍一下sdp协议&#xff0c;那实际上呢&#xff1f;sdp协议非常的简单。我们如果拿到一个stp的文档去看的话&#xff0c;那你要分阅里边的所有的内容会觉得很枯燥&#xff0c;但实际上呢&#xff0c;如果我们按照这张图所展示的结构去看stp的话。你…

Javascript每天一道算法题(十四)——合并数组区间_中等

文章目录 1、问题2、示例3、解决方法&#xff08;0&#xff09;方法0——双指针&#xff08;错误思路&#xff09;&#xff08;1&#xff09;方法1——双指针&#xff08;正确&#xff09; 总结 1、问题 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 inte…

怎么读一个网络的代码

1.网络代码怎么来的&#xff1f; 我想要实现一个功能&#xff0c;这个功能是输入一张图像&#xff0c;返回一个类别结果。 所以很明确就有三个部分&#xff0c;一个是接受图像输入&#xff0c;一个是处理图像得到处理结果&#xff0c;一个是对处理结果判断生成结果。 现在想要使…

rocketmq 发送时异常:system busy 和 broker busy 解决方案

之前写的解决方案,都是基于测试环境测试的.到生产环境之后,正常使用没有问题,生产环境压测时,又出现了system busy异常(简直崩溃).最后在rocketmq群里大佬指导下,终于解决(希望是彻底解决). 下面直接给出结果: 目前通过生产环境各种参数修改测试得出: broker busy异常: 可通…

Using PeopleCode in Application Engine Programs在应用引擎程序中使用PeopleCode

This section provides an overview of PeopleCode and Application Engine programs and discusses how to: 本节概述了PeopleCode和应用程序引擎程序&#xff0c;并讨论了如何: Decide when to use PeopleCode.决定何时使用PeopleCode。Consider the program environment.考…

Java之《ATM自动取款机》(面向对象)

《JAVA编程基础》项目说明 一、项目名称&#xff1a; 基于JAVA控制台版本银行自动取款机 项目要求&#xff1a; 实现银行自动取款机的以下基本操作功能&#xff1a;读卡、取款、查询。&#xff08;自动取款机中转账、修改密码不作要求&#xff09; 具体要求&#xff1a; 读卡…