- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
里氏替换原则的基本点是父类(super class)可以被遵循相同契约(行为)的子类替换。或者正如 Martin Fowler 所说:“使用基类指针或引用的函数必须能够在不知情的情况下使用派生类的对象。”
参数逆变被提到是 LSP 的一部分,但我似乎无法理解它为什么以及如何工作。即,在子类中,重写方法可以接受更广泛的(派生较少的参数)。
像这样:
class Base
{
int GetLenght(string s)
{
return s.lenght;
}
}
class Derived: Base
{
override int GetLenght(object s)
{
?? I cannot return any lenght of an object..
}
}
这怎么可能行得通?我的意思是,如果衍生较少的论点不具有我需要的属性,我如何遵守契约(Contract)?
PS:我确实知道大多数面向对象语言不支持这一点,我只是好奇。
最佳答案
Argument contravariance is mentioned to be a part of LSP but I cannot seem to understand why and how it can work. I.e., in a subclass, the overriding method could accept wider (less derived argument).
首先,让我们确保我们已经定义了我们的术语。
“协方差”是关系和变换的属性。。具体来说,它是在特定转换上维持特定关系的属性。 “逆变”与协方差相同,只不过它是在变换中维持但反转特定关系。
举个例子吧。我手头有一个类型,我希望按照规则 T
将其转换为不同的类型转换为Func<T>
。我在类型之间有一个关系:“X
类型的表达式可以分配给Y
类型的变量”例如,Giraffe
类型的表达式可以分配给 Animal
类型的变量。该变换是协变的,因为在整个变换过程中保留了关系:Func<Giraffe>
类型的表达式可以分配给 Func<Animal>
类型的变量.
转型T
转换为Action<T>
反转关系:Action<Animal>
可以分配给Action<Giraffe>
.
但是T
在Action<T>
是委托(delegate)所表示的方法的形参类型。正如您所看到的,我们可以在形式参数类型上实现逆变。
这对于方法重写意味着什么?当你说
class B
{
public virtual void M(Giraffe g) { b body }
}
class D : B
{
public override void M(Giraffe g) { d body }
}
这在逻辑上是相同的
class B
{
protected Action<Giraffe> a = g => { b body };
public void M(Giraffe g) { this.a(g); }
}
class D : B
{
public D() {
this.a = g => { d body };
}
}
对吗?我们用
替换 D 的构造函数是完全合法的 this.a = some Action<Animal>
对吗?然而,C#——以及大多数其他面向对象语言,但不是全部——不允许
class D : B
{
public override void M(Animal a) { d body }
}
尽管逻辑上它的工作原理与通用委托(delegate)逆变工作原理一样。这只是一个可以实现但从未实现的功能,因为还有很多更好的事情要做。
How could this ever work? I mean, how could I comply with the contract if the less derived argument does not have the properties I need?
如果你不能,那么你就不会,不是吗?
假设我需要
int CompareHeights(Giraffe g1, Giraffe g2)
我可以用一种方法来替换它,这看起来是不是太难以置信了
int CompareHeights(Animal a1, Animal a2)
?我需要一个比较长颈鹿高度的方法,我有一个比较动物高度的方法,所以我完成了,对吧?
假设我需要
void Paint(Circle, Color)
我可以用一种方法替换它,这似乎难以置信
void Paint(Shape, Color)
?这对我来说似乎是合理的。我需要一个绘制圆形的方法,我有一个绘制任何形状的方法,所以我完成了。
如果我需要
int GetLength(string)
我有
int GetLength(IEnumerable)
那我就好了。我需要一个获取字符串长度的方法,该字符串是一个字符序列。我有一个方法可以获取任何序列的长度,所以我很好。
关于oop - 里氏原理中的论证逆变如何发挥作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49834460/
今天有小伙伴给我留言问到,try{...}catch(){...}是什么意思?它用来干什么? 简单的说 他们是用来捕获异常的 下面我们通过一个例子来详细讲解下
我正在努力提高网站的可访问性,但我不知道如何在页脚中标记社交媒体链接列表。这些链接指向我在 facecook、twitter 等上的帐户。我不想用 role="navigation" 标记这些链接,因
说现在是 6 点,我有一个 Timer 并在 10 点安排了一个 TimerTask。之后,System DateTime 被其他服务(例如 ntp)调整为 9 点钟。我仍然希望我的 TimerTas
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我就废话不多说了,大家还是直接看代码吧~ ? 1
Maven系列1 1.什么是Maven? Maven是一个项目管理工具,它包含了一个对象模型。一组标准集合,一个依赖管理系统。和用来运行定义在生命周期阶段中插件目标和逻辑。 核心功能 Mav
我是一名优秀的程序员,十分优秀!