C# 代码合同:如何满足';确保未经验证';在属性getter中?

C# 代码合同:如何满足';确保未经验证';在属性getter中?,c#,code-contracts,C#,Code Contracts,我有以下界面: [ContractClass(typeof(MyObjectContract))] public interface IMyObject { int CountOfItems { get; } } 以下合同: [ContractClassFor(typeof(IMyObject))] public abstract class MyObjectContract { int IMyObject.CountOfItems { get

我有以下界面:

[ContractClass(typeof(MyObjectContract))]
public interface IMyObject
{
    int CountOfItems { get; }
}
以下合同:

[ContractClassFor(typeof(IMyObject))]
public abstract class MyObjectContract
{
    int IMyObject.CountOfItems
    {
        get
        {
            Contract.Ensures(Contract.Result<int>() > 0);
            return 1;
        }
    }
}
现在我收到一条警告说
确保未经证实:Contract.Result()>0

我该如何证明计数大于零?我不想在getter中抛出异常,我遗漏了什么


谢谢

我想,你不能用静态来证明这一点。
Enumerable.Count
扩展方法没有定义关于其返回值的任何约定(例如,此方法应为无止境序列返回什么?)


因此,CC stais checker会警告您这一点。

让我们假设您的代码是正确的。它是有效的,您只是试图让代码契约系统认识到这一事实

这特别意味着对
MyObject
的实例调用
CountOfItems
将始终返回大于零的值。它不会抛出异常,也不会返回零或更小的值

这意味着
someEnumerable
将被分配给某个对象,
someEnumerable.Count()
将始终为引用的任何对象返回大于零的值。这些事实在任何时候都是真实的(因为调用
CountOfItems
的时间没有限制)

这意味着对于
MyObject
,包含这些事实的对象有一个不变量(无论它是否在代码中明确说明)。并且由于您的代码是正确的(根据假设),MyObject的实现保证分配了
someEnumerable
,并且其计数始终大于零


因此,为了满足关于
CountOfItems
的契约,契约系统需要了解这些不变量以及如何确保它们。

正如其他人所提到的,由于基类库的限制,您无法静态证明
IEnumerable.Count()
返回的值大于0(.NET Framework)和静态检查器。但是,您可以向静态检查器表明您假定该事实为真。这是解决所有此类与基类库或静态检查器无法证明的语句的契约问题的方法

public int CountOfItems
{
    get
    {
        int count = this.someEnumerable.Count();
        Contract.Assume(count > 0);
        return count;
    }
}

向实现中添加
压缩变量
方法似乎可以解决警告问题。

它无法证明可枚举项将返回>0。但我不确定您将如何执行它。此外,我会将
某个可枚举项
更改为列表或数组,否则每次有人调用
CountOfI时它都会完全迭代tems
。您的代码暗示了一个对象不变量,
someEnumerable.Count()
将始终大于零。满足属性契约的第一步应该是在代码中显式显示该对象不变量。如何满足该不变量的详细信息取决于代码如何确保满足该不变量的详细信息。但肯定要我证明
CountOfItems
,不是吗t
Enumerable.Count
?合同是针对我的对象的行为,而不是内部实现的。除非我误解了这里的某些内容。我越想这个答案,就越觉得它是错的。在最一般的情况下,你如何证明一个属性获取者的安全性?如果我误解了你的意思,请道歉。。@马尔科姆塔克:静态检查器试图通过分析代码来证明契约。您的契约声明,
IMyObject.CountOfItems
将始终大于零。好的,静态检查器说,让我们看看代码。啊哈,调用了
Enumerable.Count
Enumerable.Count
是否保证它总是返回一个值,g是否为零?不,不是。С后果:无法静态证明该契约。这里唯一能做的就是假设(请参见
契约。假设
),那是
someEnumerable.Count>0
。好的,谢谢,我想我知道你要做什么。在一个相关的注释上——证明代码契约警告你的所有内容是必要的还是可取的?如果我不能证明这个不变量,但由于代码的结构和使用方式,确保它实际上是真的,是吗ufficient?如果我们能正式证明我们的代码是正确的,那肯定是很棒的。我实际上没有访问静态检查器的权限,所以我不知道它能做什么,但是从我从其他人那里听到的,我们还没有到能以这种方式证明一切的地步。只要你能向自己证明它是正确的,那么对事实的断言可能是合同所需的全部。但是,如果不变量依赖于此模块之外的代码(“它的使用方式”),则我不会做出断言。相反,我会继续抛出异常或其他东西。这一工作原理的示例至少会得到我的支持。
public int CountOfItems
{
    get
    {
        int count = this.someEnumerable.Count();
        Contract.Assume(count > 0);
        return count;
    }
}