gpt4 book ai didi

c# - 代码契约和继承(覆盖方法的前提条件)

转载 作者:太空狗 更新时间:2023-10-29 22:16:04 26 4
gpt4 key购买 nike

目前,代码契约不允许对派生类中的成员设置先决条件,而派生类中的成员已经在基类中设置了先决条件(实际上我目前收到的是警告,而不是错误)。我不明白这背后的逻辑。我知道这与 Liskov 的替换规则有关,该规则指出派生类应该始终能够在期望父类的地方使用。当然,“用过”意味着按预期工作。对于接口(interface),这对我来说似乎没问题,因为实现接口(interface)的不同类型不会添加状态,因此可以准确地遵守契约(Contract)。但是,当您从基类继承时,您这样做是为了添加状态和特殊功能,并且重写方法通常会有额外的要求。为什么前置条件不能像后置条件和对象不变量一样用 AND 连接在一起?

请看下面:

class Speaker
{
public bool IsPlugged { get; set; }
protected virtual void Beep()
{
Contract.Requires(IsPlugged);
Console.WriteLine("Beep");
}
}

class WirelessSpeaker : Speaker
{
public bool TransmitterIsOn { get; set; }
protected override void Beep()
{
Contract.Requires(TransmitterIsOn);
base.Beep();
}
}

您可能会争辩说此类层次结构违反了 Liskov 规则,因为无线扬声器在传递给需要 Speaker 的方法时可能无法发出蜂鸣声。但这不是我们使用代码契约的原因吗?确保满足要求?

最佳答案

代码契约不是关于满足要求,而是他们的沟通Speaker.Beep 的调用者受契约(Contract)约束,该契约(Contract)仅在某些情况下生效。

WirelessSpeaker 缩小 Speaker 的功能空间 - 这就是 Liskov 发挥作用的地方。只有当我知道它是无线的时,我才能有效地使用那个特定的Speaker。在这种情况下,我应该明确接受 WirelessSpeaker,而不是 Speaker,并避免替换问题。

编辑以回应评论:

WirelessSpeaker 的作者选择了如何解释 Beep 命令。选择一个新的契约(Contract),在这个级别可见但在基本级别不可见,施加约束,在使用 Speaker 时应用 <100% 的时间。

如果发射器未开启时它只是不发出哔哔声,我们就不会谈论代码契约(Contract)。他们的目的不是在运行时进行通信,而是在设计时进行调用的语义(不仅仅是语法)。

在运行时发生异常并最终阻止“不正确”调用的事实在很大程度上与此无关。

关于c# - 代码契约和继承(覆盖方法的前提条件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26765600/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com