《Effective C#》Item 19:推荐在继承中使用接口

C#抽象类(abstract class)与接口(interface)深度解析 本文详细探讨了C#中抽象类与接口的核心概念、主要区别、设计理念、应用场景以及高级特性。抽象类用于定义“是什么”关系,支持共享代码、状态维护和访问控制,适合作为基类使用。接口则定义“能做什么”关系,支持多重继承和松耦合设计,适合定义组件间契约。文章还对比了两者在结构、功能、版本演进等方面的差异,并提供了具体的使用场景和代码示例。此外,介绍了显式接口实现、默认接口实现等高级特性,以及抽象类与接口的组合使用方式。最后,简要分析了抽象类与接口在运行时性能上的差异。 阅读详情

.Net提供了接口,这个不同于Class或者Struct的类型定义。接口有些情况,看似和抽象类一样,因此有些人认为在.Net可以完全用接口来替换抽象类。其实不然,接口和抽象类各有长处和缺陷,因此往往在应用当中,两者要结合来使用,从而互补长短。

 

接下来先说说抽象类和接口的区别。

区别一,两者表达的概念不一样。抽象类是一类事物的高度聚合,那么对于继承抽象类的子类来说,对于抽象类来说,属于“是”的关系;而接口是定义行为规范,因此对于实现接口的子类来说,相对于接口来说,是“行为需要按照接口来完成”。这些听起来有些虚,举个例子。例如,狗是对于所有狗类动物的统称,京哈是狗,牧羊犬是狗,那么狗的一般特性,都会在京哈,牧羊犬中找到,那么狗相对于京哈和牧羊犬来说,就属于这类事物的抽象类型;而对于“叫”这个动作来说,狗可以叫,鸟也可以叫。很明显,前者相当于所说的是抽象类,而后者指的就是接口。

 

区别二,抽象类在定义类型方法的时候,可以给出方法的实现部分,也可以不给出;而对于接口来说,其中所定义的方法都不能给出实现部分。

例如:

    public abstract class AbsTest

    {

        public virtual void Test()

        {

            Debug.WriteLine( "Test" );

        }

        public abstract void NewTest();

    }

 

    public interface ITest

    {

        void Test();

        void NewTest();

    }

 

区别三,继承类对于两者所涉及方法的实现是不同的。继承类对于抽象类所定义的抽象方法,可以不用重写,也就是说,可以延用抽象类的方法;而对于接口类所定义的方法或者属性来说,在继承类中必须要给出相应的方法和属性实现。

 

区别四,在抽象类中,新增一个方法的话,继承类中可以不用作任何处理;而对于接口来说,则需要修改继承类,提供新定义的方法。

 

知道了两者的区别,再来说说,接口相对于抽象类的优势。

好处一,接口不光可以作用于引用类型,也可以作用于值类型。而抽象类来说,只能作用于引用类型。

 

好处二,.Net的类型继承只能是单继承的,也就是说一个类型只能继承一个类型,而可以继承多个接口。其实,我对于这一点也比较赞同,多继承会使继承树变的混乱。

 

好处三,由于接口只是定义属性和方法,而与真正实现的类型没有太大的关系,因此接口可以被多个类型重用。相对于此,抽象类与继承类的关系更紧密些。

 

好处四,通过接口,可以减少类型暴露的属性和方法,从而便于保护类型对象。当一个实现接口的类型,可能包含其他方法或者属性,但是方法返回的时候,可以返回接口对象,这样调用端,只能通过接口提供的方法或者属性,访问对象的相关元素,这样可以有效保护对象的其他元素。

 

好处五,减少值类型的拆箱操作。对于Struct定义的值类型数据,当存放集合当中,每当取出来,都需要进行拆箱操作,这时采用Struct+Interface结合的方法,从而降低拆箱操作。

参看如下文章提供的方法。

http://blog.youkuaiyun.com/Knight94/archive/2006/10/08/1326326.aspx

 

相对于抽象类来说,接口有这么多好处,但是接口有一个致命的弱点,就是接口所定义的方法和属性只能相对于继承它的类型(除非在继承类中修改借口定义的函数标示),那么对于多层继承关系的时候,光用接口就很难实现。因为如果让每个类型都去继承接口而进行实现的话,首先不说编写代码比较繁琐,有时候执行的结果还是错误,尤其当子类型对象隐式转换成基类对象进行访问的时候。

那么这时候,需要用接口结合虚方法来实现。参看IDisposable在继承类型中的实现方法。

http://blog.youkuaiyun.com/Knight94/archive/2006/10/10/1329214.aspx

 

其实在继承中,到底使用接口还是抽象类。接口是固定的,约定俗成的,因此在继承类中必须提供接口相应的方法和属性的实现。而对于抽象类来说,抽象类的定义方法的实现,贯穿整个继承树,因此其中方法的实现或者重写都是不确定的。因此相对而言,抽象类比接口更灵活一些。

 

如下给出两者的简单对比表格。

 

接口

抽象类

多继承

支持

不支持

类型限制

没有

有,只能是引用类型

方法实现

继承类型中必须给出方法实现

继承类中可以不给出

扩展性

比较麻烦

相对比较灵活

多层继承

比较麻烦,需要借助虚函数

比较灵活

 

总的来说,接口和抽象类是.Net为了更好的实现类型之间继承关系而提供的语言手段,而且两者有些相辅相成的关系。因此我并不强调用什么而不用什么,那么问题的关键在于,如何把这两种手段合理的应用到程序当中,这才是至关重要。

 
Effective C++与现代C++实践:从RAII到智能指针的编程哲学 在C++编程中,资源管理和内存安全是构建健壮系统的核心基础。RAII(Resource Acquisition Is Initialization)作为一种关键编程范式,通过将资源生命周期与对象绑定,从根本上解决了资源泄露问题。这一原理在现代C++中通过智能指针(如std::unique_ptr、std::shared_ptr)得到了优雅实现,它们不仅自动管理动态内存,还通过所有权语义确保了异常安全。这些技术对于开发高性能服务器、游戏引擎等对稳定性要求极高的应用场景至关重要。本文以《Effective C+ 阅读详情

相关推荐

C#核心特性与开发实践全解析

面向对象编程是现代软件开发的基础范式,C#作为.NET平台的主力语言,通过统一的类型系统和自动内存管理机制实现了高效开发。其核心特性包括泛型编程确保类型安全、LINQ实现声明式数据操作、async/await简化异步编程,这些技术显著提升了工程实践中的开发效率和代码质量。特别是在企业级应用开发中,C#的反射机制和特性系统为元编程提供了强大支持,而委托与事件模型则完善了观察者模式的实现。随着.NET生态的跨平台发展,C#结合Visual Studio等工具链,已成为Web服务、桌面应用和游戏开发等场景的热门选

weixin_30254435的博客 408

c#接口和抽象类的区别

c#接口和抽象类的区别 大家都容易把这两者搞混,我也一样,在听李建忠老师的设计模式时,他也老把抽象类说成接口,弄的我就更糊涂了,所以找了些网上的资料. 一、抽象类: 抽象类是特殊的类,只是不能被实例化;除此以外,具有类的其他特性;重要的是抽象类可以包括抽象方法,这是普通类所不能的。抽象方法只能声明于抽象类中,且不包含任何实现,派生类必须覆盖它们。另外,抽象类可以派生自一个抽象类,可以覆盖基类的抽象方法也可以不覆盖,如果不覆盖,则其派生类必须覆盖它们。 二...

huang714的专栏 4471

Azure Blob Storage企业级数据管理:上传、安全与自动化策略

对象存储是现代数据平台的基础设施核心,其本质是为海量非结构化数据提供高可靠、低成本、强一致性的持久化能力。Azure Blob Storage 作为典型代表,通过 RESTful 接口、分层存储(Hot/Cool/Archive)、生命周期策略等机制,实现数据从写入到归档的全周期治理。技术价值在于将权限控制(RBAC + SAS)、加密(SSE/CMK)、网络隔离(VNet/Firewall)深度集成于服务原生能力中,显著降低合规风险与运维复杂度。典型应用场景包括医疗影像归档、IoT日志沉淀、备份数据湖构建

dengwan3818的博客 382

浅谈C#中的抽象类(abstract)和接口(interface)

很多C#的初学者在编程时都容易把抽象类和接口搞混,甚至很多编程老鸟也没有弄明白为什么有了抽象类又搞个接口(这里也包括了本老鸟)。所以这里整理了C#抽象类和接口的区别,详细的分析了抽象类与接口的概念与特性,并对二者作出比对说明。

MarcoPro的博客 4727

C++ 知识补充

向量(vector)是一个封装了动态大小数组的顺序容器(SequenceContainer)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。C++中map提供的是一种键值对容器,里面的数据都是成对出现的,如下图:每一对中的第一个值称之为关键字(key),每个关键字只能在map中出现一次;第二个称之为该关键字的对应值。

weixin_47059239的博客 2130

【继承抽象类和接口的区别】

【继承抽象类和接口的区别】

学无止境 642

Effective C# Item29:只有当新版基类导致问题时才考虑使用new修饰符

我们一般在类成员上使用new修饰符,来重新定义继承自基类的非虚成员,但是我们不建议这么做,因为重新定义非虚方法会导致含混不清的行为。 非虚方法是静态绑定的,编译器并不会根据对象的运行时类型来判断应该调用哪个方法;而虚函数使用的是动态绑定,编译器会根据对象的运行时类型来判断应该调用哪个方法。 避免使用new 修饰符来重新定义非虚方法,并不是说你应该将基类中的所有方法都设计...

weixin_30916125的博客 56

C# 中抽象类与接口的异同

抽象类和接口在 C# 编程中各有其独特的价值。开发者应根据具体的需求来选择使用抽象类还是接口,或者结合两者使用,以构建出更加灵活、可维护的软件系统。如果需要定义一组具有部分实现的通用行为且强调代码复用和层次结构,可选择抽象类;如果需要定义一组行为规范且强调行为的一致性和多态性,接口则是更好的选择。在 C# 编程中,抽象类和接口都是实现代码复用和多态性的重要工具,但它们在很多方面存在差异。理解这些异同,有助于开发者在实际项目中做出恰当的选择,以构建高效且可维护的软件系统。

candy的博客 1533

2024年C++程序员成长路线图:从新手到架构师的完整路径

C++作为一种高性能系统编程语言,其核心价值在于对计算机底层原理的深度控制和高性能计算能力。其设计哲学融合了面向对象、泛型和过程式编程范式,通过RAII(资源获取即初始化)等机制实现安全高效的资源管理。在现代软件开发中,C++的技术价值体现在操作系统、游戏引擎、高频交易、数据库等对性能和可靠性要求极高的领域。随着AI基础设施和边缘计算的发展,掌握C++底层原理和大型系统架构能力成为工程师的核心竞争力。本文基于C++11/14/17/20的现代特性,结合多线程编程、智能指针、STL容器等热词,系统梳理了从语言

weixin_33709609的博客 521

ArcGIS License Server点击启动没反应,许可管理器无法启动怎么办

4 当我们再打开ArcGIS License Server Administrator的时候。3 在【服务】中找到【ArcGIS License Manager】双击。无法启动ArcGIS License Server的情况。在使用ArcGIS的过程中,我们经常会遇到。专注GIS领域知识分享,交流行业软件技巧。欢迎关注,不定期分享GIS各种问题和技巧。1 右击我的电脑——【管理】服务状态——启动,确定即可。启动类型选择——自动。

GIS蒲公英的博客 2万+

CANoe UDS $27服务DLL生成实战:从工程配置到算法修改全流程

本文详细介绍了在Vector CANoe中为UDS(统一诊断服务)的$27安全访问服务生成定制化DLL(动态链接库)的全流程。从定位官方参考工程、配置Visual Studio开发环境,到深入解析核心的GenerateKeyEx函数接口,并重点演示了如何修改和实现自定义的种子-密钥安全算法,最终完成DLL的编译、部署与CANoe集成测试,为汽车电子诊断开发提供实战指导。

star5的专栏 534

C++编程语言深度解析:从核心设计到现代应用实战指南

编程语言作为计算机系统的核心沟通工具,其设计哲学直接影响软件的性能、安全性与可维护性。在众多编程范式中,面向对象编程通过封装、继承和多态等机制,构建出模块化、可复用的代码结构,而泛型编程则借助模板技术实现类型无关的通用算法,这两者共同构成了现代软件工程的基石。C++作为一门支持多范式的中级语言,其独特价值在于实现了“零开销抽象”原则,使得高级编程特性几乎不带来额外运行时损耗,从而在系统软件、游戏引擎、高频交易等对性能有极致要求的领域不可替代。通过智能指针等现代特性,C++在保持底层控制力的同时大幅提升了内存

weixin_34342207的博客 417

共模电感在EMI滤波中的实战应用与设计技巧

本文深入探讨了共模电感在EMI滤波中的关键作用与设计技巧,涵盖电感值选择、饱和电流风险、磁芯材料性能及绕组工艺等实战经验。通过具体案例解析,展示了共模电感在开关电源、高速接口及汽车电子中的高效应用,帮助工程师解决电磁兼容问题并提升信号完整性。

weixin_27051161的博客 417

让AI Agent准确生成代码文档:意图对齐与提示词实战指南

AI Agent正从对话问答走向自动化执行,尤其在代码生成、测试与文档维护领域展现出巨大潜力。但要让Agent真正理解你的需求,而非自由发挥,核心在于意图对齐。通过精确的提示词设计、结构化上下文供给与工具调用,Agent能力边界可以被显著扩展。本文从代码文档生成这一典型高频场景切入,讲解如何利用AST解析、上下文工程与一致性校验,构建一个可落地的文档Agent。结合OpenAI兼容接口与Python工具链,展示从模糊指令到精确任务拆解的方法论,并探讨多轮探索式Agent的工程实践。无论你关注智能体开发、自动

weixin_30861797的博客 352

MATLAB 基于 Baker 映射和 Logistic 混沌序列的图像加解密实现

图像加密是信息安全领域的重要研究方向,在数字版权保护、隐私保护等领域有着广泛应用。本文将介绍基于 MATLAB 的 Baker 映射和 Logistic 混沌序列的图像加解密算法,该算法利用混沌系统的初值敏感性和伪随机性,能够有效地对图像进行加密和解密。基于 Baker 映射和 Logistic 混沌序列的图像加解密算法是一种有效的方法,可以应用于数字版权保护、隐私保护等领域。MATLAB 提供了强大的工具和函数,可以方便地实现该算法。

走向CTO的路上... 935

SeaTunnel 实战:Apache SeaTunnel Web 安装与部署

复制引擎服务中配置文件到 Web 配置目录下面。就是上述 application.yml 文件中配置的端口号。默认是从 mvvm 下载,可能下载速度很慢,我这边安装了 Maven 并且配置了阿里云仓库,因此将脚本中的。如果环境变量有冲突需要改下环境变量的名字以及 init_sql.sh 中的环境变量的名字,可以加上前缀。初始化数据库有两种方式,一是使用官方提供的初始化脚本,二是直接运行初始化 SQL。初始化数据库的脚本,使用之前需要修改。

SmartSi 3909

C++AI编译错误自动修复神器-告别手动Debug的终极方案

在日常 C++ 开发中,编译错误是最频繁遇到的障碍之一。一个中等规模的项目在重构期间,一次 可能产生数十甚至上百条错误信息。这些错误往往具有级联效应——一个头文件的拼写错误可能导致下游十几个翻译单元同时报错,而真正需要修改的地方只有一处。传统的工作流是: 这个循环对于经验丰富的开发者来说尚可接受,但对于以下场景则效率极低:优势:局限:本项目最适合以下场景:阅读

weixin_48053866的博客 280

为何wait和notify方法必须加锁?

为何wait和notify方法必须加锁? 是为了避免Lost Wake Up问题,即丢失唤醒问题。 所谓Lost Wake Up,指的是:线程A调用wait()方法进入阻塞状态,接下来没有其他线程去唤醒线程A,或者其他线程唤醒的时机不对(早于线程A的wait()),导致线程A永远阻塞下去。 下面以一个生产者和消费者的案例来说明上述问题。 假如我们有两个线程,一个消费者线程,一个生产者线程。生产者线程的任务可以简化成将count加一,而后唤醒消费者;消费者则是将count减一,而后在减到0的时候陷入睡眠,.

打酱油的葫芦娃 9155

C# 抽象类与接口的区别

一、定义   抽象类:不与具体事物相联系,表达一种抽象的概念,仅是作为其派生类的一个基类。主要用来提供多个派生类可共享的基类的公共定义。   接口:是一种用来定义程序的协议,它描述可属于任何类或结构的一组相关行为,可以看成是实现一组类的模板。 二、相似之处   1.都是引用类型   2.不能直接实例化   3.包含未实现的方法声明   4.派生类必须实现未...

weixin_30902675的博客 1368

PyCharm安装PyQt5及工具详细教程

PyCharm是一款功能强大的Python集成开发环境(IDE),而PyQt5是一个用于创建GUI应用程序的流行Python库。在本教程中,我将指导您如何在PyCharm中安装PyQt5及其相关工具,并提供相应的源代码示例。安装完成后,启动PyCharm并创建一个新的项目。为了隔离项目的依赖项,我们建议在PyCharm中使用虚拟环境。在创建项目的过程中,您可以选择创建新的虚拟环境或使用现有的环境。根据您的操作系统,选择适当的版本并按照安装向导的指示进行安装。首先,您需要下载并安装PyCharm。

CfProgram的博客 588

十四种逻辑器件综合对比——《器件手册--逻辑器件》

逻辑器件是数字电路中最基本的逻辑单元,用于实现基本的逻辑运算,如与、或、非、异或等。逻辑门根据输入信号的组合产生相应的输出信号。与门:只有当所有输入信号都为高电平时,输出才为高电平。或门:只要有一个输入信号为高电平,输出就为高电平。非门:输出信号与输入信号相反。异或门:当两个输入信号不同时,输出为高电平;相同则输出为低电平。用于对输入信号进行反相操作,即将高电平转换为低电平,低电平转换为高电平。常用于信号的反相处理和逻辑电平的转换。

XU157303764的博客 2029

C# 接口和抽象类的区别

一、抽象类 抽象类是仅供派生的类,无法实例化抽象类,只能实例化它派生的类。 定义抽象类和抽象成员时,要为其添加abstract修饰符。 不可实例化只是抽象类的一个次要的特征,其主要特征是它包含抽象成员。 抽象成员不能声明为私有,否则,派生类无法找到它们。 二、接口 1.和抽象类不同,接口不包含任何实现,而且,接口能把提供的服务和实现细节完全隔离开。 2.关键特点:既不包含实现,也不包含数据。...

mozhi 1976

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

上一篇: 借助WebService实现多线程上传文件
下一篇: 怎么用C#制作印章
Knight94
博客等级 码龄25年 1013粉丝 87原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值