【问题标题】:Code Contracts: Require an IEnumerable to be non-empty代码契约:要求 IEnumerable 为非空
【发布时间】:2011-05-29 02:01:11
【问题描述】:

我有以下代码:

public static IEnumerable<long> GetAllCombinations(IEnumerable<long> elements)
{
    Contract.Requires(elements != null);
    return GetAllCombinations(elements.ToList(), 0);
}

静态分析现在告诉我添加另一个前提条件:

CodeContracts:建议的前提条件: Contract.Requires(最大值 >= 0)

我不明白这个建议,因为

a) 如果我已经确保 elements 不为 null,我为什么要检查它的计数是否更大或 等于 为零?我的意思是,传递一个非空值已经意味着它至少包含零个元素?

b) 我应该如何检查 IEnumerable 的计数(或建议的最大值)?我看到的唯一方法是将elements.ToList() 分配给一个额外的变量并检查该变量。但是,如果我不想从 IEnumerable 中列出列表呢?

让我感到困惑。

编辑:

我知道IEnumerable&lt;T&gt; 的所有扩展方法,并且非常了解.Any().Count() 等。

让我困惑的是来自静态分析器的消息。谁能解释为什么它声明Contract.Requires(maximum &gt;= 0)

这是否意味着我认为的意思(检查元素数量 >= 0)?

而且,正如评论中提到的,为什么静态分析器仍然对Contract.Requires(elements.Any()); 不满意?

【问题讨论】:

  • 如果元素为空,elements.Any() 将失败。这可能是您的问题。
  • @Aren:我还有第一次检查 null,所以这不是问题。
  • 静态分析器的启发式分析可能不够智能,无法链接您的合约。我只是在说明人们对IEnumerable&lt;T&gt; 的实现怀念的一个共同点。试试Contract.Requires(elements != null &amp;&amp; elements.Any()) 看看警告是否消失。
  • 我认为您正在寻找错误的方法。当 CodeContracts 说“maximum >= 0”时,它指的是这里不存在的参数。 CodeContracts 是否有可能从输出到方法提供了错误的“链接”?
  • @Porges:我开始这么想了。好像静态分析器深入研究了框架源代码并指出了Enumerable.ToList() 的实现中的一些变量。今晚我需要验证一下。

标签: c# c#-4.0 code-contracts


【解决方案1】:

elements.Count&lt;long&gt;() 将为您提供IEnumerable&lt;long&gt; 的计数。您仍然需要检查计数,因为某些方法会在空 IEnumerable(例如,Single)上引发异常。

【讨论】:

  • 请记住,Count() 最终会运行在整个 IEnumerable 上——这可能会很昂贵。如果您只想检查 IEnumerable 是否为空,请改用Any() 方法。
  • 非常正确。我忘记了 Any()
【解决方案2】:

我的意思是,传递一个非空值 已经意味着它至少包含 零元素?

没有。相当多的返回 IEnumerable 的 API#s 确实总是返回一些东西 - 只是空的。

我应该如何检查计数 (或最大值,如建议的那样) IEnumerable?

这实际上是真正的问题。 Enumerable 没有相应的 API。

【讨论】:

  • 一个空的 IEnumerable 仍然有零个元素?
  • @VVS,是的 Enumerable.Empty() 可能已被传递,其中不包含任何元素。
  • @Gary:是的,我已经知道 IEnumerable 可以有零个或多个元素。这就是为什么我想知道为什么代码合同要我明确检查这种情况。再读一遍我的论点。
  • @VVS,对不起,我在回答这个问题:“一个空的 IEnumerable 仍然有零个元素?”
  • @Gary:啊,这更像是一个陈述而不是一个问题。
【解决方案3】:

我不确定为什么静态分析建议检查集合的计数。如果传递了一个空集合,则评估它的代码将不会执行(即foreach 语句),这应该没问题。也许这与集合的Count 是签名类型有关?您可能想尝试使用 Contracts.Assume(elements.Any()) 之类的内容或声明计数为非负数的语句来满足静态分析器的要求。

要解决您的第二个问题,有很多方法可以确定 IEnumerable&lt;&gt; 结构是否为非空。列举几个,由System.Linq 命名空间启用:

  • elements.Any() // 检查是否存在至少一个元素,O(1)。
  • elements.Count() // 统计所有元素,O(n)
  • elements.Single() // 如果存在多个元素,则引发异常,O(1)。
  • elements.First() // 返回第一个元素,如果为空则引发异常,O(1)。

以下两种变体等价于elements.Any(),其中T是容器中元素的类型:

  • elements.SingleOrDefault() != default(T)
  • elements.FirstOrDefault() != default(T)

【讨论】:

  • Contract.Requires(elements.Any()); 给出了静态分析器的相同建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多