0

0

C# 里氏替换原则LSP C#继承中如何遵循LSP

煙雲

煙雲

发布时间:2026-03-04 08:37:03

|

369人浏览过

|

来源于php中文网

原创

virtual + override 是底线要求,因lsp要求“替换后行为不变”;若父类未声明virtual而子类用new隐藏,则父类引用调用时仍执行父类逻辑,违背lsp透明性前提。

c# 里氏替换原则lsp c#继承中如何遵循lsp

子类重写方法时,为什么 virtual + override 是底线要求?

因为 LSP 的核心是“替换后行为不变”——如果父类方法没声明为 virtual,子类用 new 隐藏它,那通过父类引用调用时,实际执行的仍是父类逻辑,根本不是子类对象在“替换”,而是被悄悄绕开了。这直接违反 LSP 的透明性前提。

  • ✅ 正确:父类用 virtual void Work(),子类用 override void Work()Animal a = new Cat(); a.Work() 真正调用 Cat.Work()
  • ❌ 危险:父类是普通 void Work(),子类用 new void Work(),同样代码会调用 Animal.Work(),子类行为完全不可见
  • ⚠️ 注意:override 不能改返回类型、不能扩大访问修饰符(比如父类 protected,子类不能 public override),否则编译报错,本质就是在强制守 LSP 的契约边界

构造函数链中,base() 调用不当怎么偷偷破坏 LSP?

父类构造函数常承担状态初始化(如校验必填字段、设置默认值)。若子类构造函数没显式调用合适的 base(...),而依赖默认无参构造,可能导致父类关键字段未初始化或被设为非法值——这时子类对象虽然能创建,但一调用继承来的方法就抛异常,等同于“我爸会开车,我坐上驾驶座却打不着火”。

ChatGPT Writer
ChatGPT Writer

免费 Chrome 扩展程序,使用 ChatGPT AI 生成电子邮件和消息。

下载
  • 父类有带参构造且没提供无参构造 → 子类必须用 : base(x, y) 显式传递合法参数
  • 若父类构造中做了非空检查(如 if (name == null) throw ...),子类传 null 就直接崩,这不是多态问题,是构造阶段就违背了“子类应能胜任父类所有使用场景”
  • 建议:父类构造函数尽量做最小必要初始化;复杂校验可推迟到虚方法中,由子类按需 override 实现

属性和字段的继承,哪些地方最容易踩 LSP 的“行为不一致”坑?

字段本身不参与多态,但属性的 get/set 可以被重写。常见陷阱是子类重写 set 时加了新约束(比如只允许正数),但父类契约没声明这个限制——外部代码按父类文档设负数,运行时突然炸,这就是后置条件弱化(LSP 明确禁止)。

  • 父类属性 public virtual int Speed { get; set; } 意味着“任何 int 都可赋值”,子类 overrideset 就不能 throw 或静默修正值
  • 若真需要约束,应在父类就把契约写清楚:比如改为 protected virtual void ValidateSpeed(int value),子类可重写验证逻辑,但父类 set 里仍统一调用它
  • 私有字段永远继承但不可见,所以别指望子类靠改父类私有字段来“修正行为”——那是黑盒操作,LSP 要求的是公开契约层面的兼容

is / as 做类型判断时,为什么反而暴露 LSP 设计缺陷?

真正符合 LSP 的继承体系,应该不需要在运行时反复判断“你到底是哪个子类”。一旦出现 if (obj is Cat) ((Cat)obj).Meow(); else if (obj is Dog) ((Dog)obj).Bark();,说明父类抽象不足,子类行为已脱离统一接口,此时用多态调用 obj.MakeSound() 才是正解。

  • as 强转失败返回 null,看似安全,但掩盖了“本该通用却硬要分支处理”的设计债
  • 如果业务逻辑确实需要区分类型(如日志记录不同子类的专属字段),优先考虑用虚方法或抽象方法暴露差异点,而不是让调用方去拆箱
  • 一个信号:当你写完 as 还得补 if (result != null),大概率说明父类缺少必要的虚成员来承载这种变化
LSP 不是语法检查器,它藏在每次父类引用调用子类方法的那一刻——只要那个调用结果和父类文档承诺的不一致,哪怕只差一行日志、一个返回码、一次静默截断,就是破约。最隐蔽的破约,往往发生在没人写的测试用例里。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

252

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

988

2024.03.01

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

839

2023.08.22

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

27

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

27

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

27

2025.11.27

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

910

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

600

2024.08.29

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

3

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 10.6万人学习

C 教程
C 教程

共75课时 | 5.2万人学习

C++教程
C++教程

共115课时 | 20.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号