关于c#:Liskov替换原则,前提条件和抽象方法

Liskov substitution principle, preconditions and abstract methods

Liskov替代原则(LSP)表示:

Preconditions cannot be strengthened in a subtype.

在C中,我可能违反以下整个原则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class A
{
      public virtual void DoStuff(string text)
      {
            Contract.Requires(!string.IsNullOrEmpty(text));
      }
}

public class B : A
{
      public override void DoStuff(string text)
      {
            Contract.Requires(!string.IsNullOrEmpty(text) && text.Length > 10);
      }
}

但是,如果A.DoStuffabstract方法,会发生什么情况:

1
2
3
4
5
6
7
8
9
10
11
12
public class A
{
      public abstract void DoStuff(string text);
}

public class B : A
{
      public override void DoStuff(string text)
      {
            Contract.Requires(!string.IsNullOrEmpty(text));
      }
}

现在,A.DoStuff是无契约的。或者它的合同只是允许的。

那么,B.DoStuff前提条件是否违反了Liskov替换原则?


这取决于合同的定义。

LSP是一个理论结构,它不依赖于特定的语言或实现,例如C的"代码契约"特性。

合同的定义如下:

  • 方法名称
  • 方法参数名称
  • 方法注释
  • 返回类型和方法参数类型
  • "明确"合同,如Contract.Requires

最后两个将由编译器验证。然而,前三个也可以是合同的一部分!请考虑以下示例:

1
2
3
4
5
6
7
public interface StuffContainer
{
    void Add(string text);

    // Removes a string that has previously been added.
    void Remove(string text);
}

Remove方法的名称和文档定义了一个明确的前提条件。在实现中验证要删除的字符串以前是否已添加,不会违反LSP。验证字符串是否至少有5个字符将违反LSP。


是的,你可以很容易地打破这个原则,不仅仅是在C。

它只陈述:

Subtype Requirement: Let phi(x) be a
property provable about objects x of type T. Then
phi(y) should be true for
objects y of type S where S is a subtype of T.

在您的示例中,类型B不满足提供与短文本一起工作的方法DoStuff的属性,尽管它的超类型A实现了它。所以这一原则被违反了。

坚持这一原则取决于程序员。属性也可以是"它做了正确的事情",您可以很容易地通过拥有具有错误方法实现的子类型来破坏它。


我认为不是。定义的抽象方法没有前提条件,因为没有实现。如果实现一个接口会破坏LSP,这与争论是一样的。

说EDOCX1[1]是反的是一个不真实的前提。A.DoSomehing()是未定义的,因此只有在其签字之后才能有合同。