为什么可以为后置条件和对象不变量添加和删除代码协定,而不能为 C# 中的前提条件添加和删除代码协定?

Why code contracts can be added and removed for postconditions and object invariants, but not for preconditions in C#?

提问人:qqqqqqq 提问时间:2/21/2020 最后编辑:qqqqqqq 更新时间:2/21/2020 访问量:131

问:

为什么可以为后置条件和对象不变量添加和删除代码协定,而不能为 C# 中的前提条件添加和删除代码协定?

在《CLR via C#》一书中,我看到了以下摘录:

而且,由于新版本无法使合同更严格(不破坏兼容性),因此您 在引入新的虚拟、抽象或接口成员时,应仔细考虑前提条件。对于后置条件和对象不变量,可以随意添加和删除合约作为条件 在 virtual/abstract/interface 成员中表示,在重写中表示条件 成员只是在逻辑上 AND-ed 在一起

这让我非常困惑,后置条件和对象不变量,合约可以随意添加和删除。我期望有人建议后置条件和对象不变量只会变得更严格,前提条件也会变得更严格。我为什么期待这个?因为我可以举出一个例子,说明这个建议被证明是错误的。例如

起初我们有一个后置条件,一切正常:

using System.Diagnostics.Contracts;

public sealed class Program
{
    public static void FooBaseContract(int i) 
    {
        Contract.Ensures(i > 0);
    }
}

public class FooBase 
{
    public virtual int i 
    {
        get {return 2;} 
    }
}
public class FooDerived : FooBase
{
    public override int i 
    {
        get {return 4;} 
    }
}

现在我们决定使后置条件更严格:

using System.Diagnostics.Contracts;

public sealed class Program
{
    public static void FooBaseContract(int i) 
    {
        Contract.Ensures(i > 4);
    }
}

public class FooBase 
{
    public virtual int i 
    {
        get {return 2;} 
    }
}
public class FooDerived : FooBase
{
    public override int i 
    {
        get {return 4;} 
    }
}

这肯定会使使用前一个后置条件的代码与新后置条件不兼容。这意味着我们通过使后置条件更严格而失去了向后兼容性。

另外,我不明白为什么作者只提到.因为在我上面给出的人为示例中,即使我将代码更改为以下内容(全部删除),也会发生与新代码合约版本不兼容的情况:virtual, abstract, or interface membervirtual, abstract, or interface member

using System.Diagnostics.Contracts;

public sealed class Program
{
    public static void FooBaseContract(int i) 
    {
        Contract.Ensures(i > 4);
    }
}

public class FooBase 
{
    public int i 
    {
        get {return 2;} 
    }
}

那么,有人可以以万无一失的方式解释一下我在这里错过了什么吗?

更新

正如评论部分提到的 - 代码协定是一个不推荐使用的概念。这对我来说没关系,我只是想理解这个想法 - 在这种情况下,为什么我们可以使后置条件和对象不变量更严格?这与我的常识相矛盾,这意味着以前允许返回某些东西(或为对象不变量而发生),现在我们声明不再允许某些东西,这本书的作者告诉这种情况不会破坏向后兼容性。

C# 代码协定

评论

0赞 Samuel Liew 2/21/2020
评论不用于扩展讨论;此对话已移至 Chat

答:

1赞 usr 2/21/2020 #1

文中说,这些条件是“和”在一起的。这意味着您根本无法删除后置条件和不变量。无论您如何编写代码,都只能添加它们。

后置条件和不变量是退出时必须确保的东西。能够增加义务是有道理的。如果您要添加矛盾,则 CC 应将其标记为后置条件冲突。

从兼容性和扩展性的角度来看,基类的用户将获得他们期望的保证。他们可能会收到他们不知道或不关心的额外保证。