首页 / 知识
关于c#:为什么继承不按我认为应该起作用的方式工作?
2023-04-14 09:28:00

Why doesn't inheritance work the way I think it should work?我遇到了一些继承问题,因为我有一组相互关联的抽象类,需要将它们全部一起重写以创建客户端实现。理想情况下,我想执行以下操作:
这将允许使用Dog类的任何人自动获取DogLegs,以及使用Animal类的任何人获取Legs。问题在于,重写的函数必须具有与基类相同的类型,因此它将无法编译。我不明白为什么不应该这样做,因为DogLeg可隐式转换为Leg。我知道有很多解决办法,但是我很好奇为什么在C#中不可能/无法实现。 编辑:我做了一些修改,因为我实际上在代码中使用属性而不是函数。 编辑:我将其更改回函数,因为答案仅适用于这种情况(属性的set函数的value参数的协方差不起作用)。对不起,波动!我意识到这使得很多答案似乎无关紧要。 简短的答案是GetLeg的返回类型不变。长答案可以在这里找到:协方差和协方差 我想补充一点,虽然继承通常是大多数开发人员从其工具箱中提取的第一个抽象工具,但几乎总是可以使用合成代替。对于API开发人员而言,组合工作要稍微多一些,但会使API对它的使用者更有用。
显然,如果您是 Dog应该返回腿而不是DogLeg作为返回类型。实际的类可能是DogLeg,但是关键是要解耦,因此Dog的用户不必了解DogLegs,他们只需要了解Legs。 更改:
至:
不要这样做:
它违反了编程为抽象类型的目的。 隐藏DogLeg的原因是因为抽象类中的GetLeg函数返回了抽象腿。如果要覆盖GetLeg,则必须返回Leg。那就是在抽象类中具有方法的意义。将该方法传播给孩子。如果您希望Dog的用户了解DogLegs,请创建一个名为GetDogLeg的方法并返回DogLeg。 如果您可以按问问者的意愿进行操作,那么Animal的每个用户都需要了解所有动物。 让签名的重写方法具有返回类型是重写方法(phew)中返回类型的子类型,这是一个完全正确的愿望。 毕竟,它们是运行时类型兼容的。 但是C#尚不支持重写方法中的"协变量返回类型"(与C ++ [1998]和Java [2004]不同)。
正如埃里克·利珀特(Eric Lippert)在他的博客中所说,您需要努力并为可预见的未来做好准备。
这样做,然后可以在客户端中利用抽象:
然后,如果需要,可以将其转换为:
完全是人为的,但重点是您可以这样做:
同时仍然保留对Doglegs使用特殊驼峰方法的能力。 您可以使用泛型和接口在C#中实现:
并不是说它有很多用处,但是可能有趣的是注意到Java确实支持协变量返回,因此这完全可以按照您的期望工作。显然除了Java没有属性;) 在http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)中描述了导致您出现问题的概念。 GetLeg()必须返回Leg作为重写。但是,由于Dog类是Leg的子类,因此您的Dog类仍然可以返回DogLeg对象。然后,客户可以像狗狗一样投下并对其进行操作。
也许通过示例更容易看到问题:
现在,如果您是Dog编译的,那应该可以编译,但是我们可能不想要这样的变体。
一个相关的问题是Dog []应该是Animal [],还是IList C#具有显式的接口实现来解决此问题:
如果通过类型Dog的引用拥有Dog,则调用GetLeg()将返回DogLeg。 如果您具有相同的对象,但是引用的类型为IAnimal,则它将返回Leg。 @卢克 我认为您也许对继承有误解。 Dog.GetLeg()将返回DogLeg对象。
实际调用的方法是Dog.GetLeg();和DogLeg.Kick()(假设存在Leg.kick()方法),则不需要声明的返回类型为DogLeg,因为即使Dog.GetLeg()的返回类型为腿。
@布莱恩·莱希 要记住的重要一点是,可以在使用基本类型的每个位置使用派生类型(可以将Dog传递给需要Animal的任何方法/属性/字段/变量) 让我们使用以下功能:
一个完美有效的函数,现在让我们这样调用该函数:
如果属性Dog.Leg不是Leg类型,则AddLeg函数突然包含错误,无法编译。 是的,我知道我可以施放,但这意味着客户必须知道Dogs有DogLegs。我想知道的是,鉴于存在隐式转换,是否有技术原因无法做到这一点。 您可以通过使用具有适当约束的泛型来实现所需的目标,如下所示:
您还可以返回Leg和/或DogLeg都实现的接口ILeg。 |
最新内容
相关内容
linux命令测试客户端?
linux命令测试客户端?,地址,系统,网络,工具,工作,分析,环境,命令,下行,资料,linux测试网速的工具1、speedtest-cli是一个用Python编写的轻量级go操作linux命令?
go操作linux命令?,系统,工具,环境,软件,标准,网上,最新,信息,设备,电脑,Linux启动进程的命令1、实现调度启动进程的方法有很多,比如通过crontablinux命令操作vim?
linux命令操作vim?,系统,地址,工作,命令,模式,标准,信息,入口,连续,时间,Linux基础-vim模式普通模式用的编辑器命令,比如移动光标,删除文本等等linux操作不了命令?
linux操作不了命令?,系统,密码,不了,命令,位置,信息,情况,网络,地址,定期,linux命令不可用1、这个方法应该适合任何没有连接网络的情况,在命令linux运维操作命令?
linux运维操作命令?,系统,网络,基础,标准,工具,信息,工作,命令,软件,数据,linux运维命令常用命令1、ls, ls-l, less, head, tail, tail -f, ln, ln -slinux命令行常见操作?
linux命令行常见操作?,系统,工作,地址,管理,信息,命令,目录,一致,基础,标准,linux系统怎么用1、Linux的用处linux是一套免费开放源代码的操作linux清空操作命令?
linux清空操作命令?,系统,数据,命令,名称,不了,文件夹,文件,环境,回收站,目录,删除文件夹中所有文件的linux命令(创建和删除文件和文件夹的linlinux安装操作命令?
linux安装操作命令?,系统,工作,地址,工具,服务,情况,信息,命令,最新,管理,linux系统常用操作命令1、linux常用命令有pwd命令、cd命令、ls命令linux操作系mv命令?
linux操作系mv命令?,名字,系统,软件,文件,命令,信息,地址,目录,文件夹,源文件,Linux中的文件与目录操作利器mv命令使用解析1、mv file_txt /holinux操作命令大全图?
linux操作命令大全图?,工作,地址,系统,信息,命令,目录,控制台,功能,操作,内核,Linux实用命令有哪些?1、linux系统常用操作命令如下:ls:全拼list,linux操作命令论文?
linux操作命令论文?,管理,系统,设计,网络,企业,基础,机电设备,技术,发展,机电,跪求有关linux的起源,发展,现状,应用领域和发展前景的小论文!年linux操作命令cp?
linux操作命令cp?,系统,文件,命令,源文件,基本知识,时间,目录,文件夹,选项,目标,linux复制命令1、linux系统使用cp命令即可将一个文件夹里面的