【问题标题】:.NET 4 Code Contracts: do I need to include the same contracts twice?.NET 4 代码合同:我是否需要包含两次相同的合同?
【发布时间】:2010-06-29 13:24:15
【问题描述】:

假设我有一个方法public void Foo(string bar),调用者不应使用空值bar 调用它。假设我也有一个方法,称为private void FooImpl(string bar),它执行Foo 的实际工作。当然,FooImpl真正需要bar 的非空性,即使Foo 是公共接口。假设我想使用 .NET 4.0 代码合同来强制执行这种非空性。

我把合同放在哪里?

如果我这样做:

public void Foo(string bar)
{
  this.FooImpl(bar);
}

private void FooImpl(string bar);
{
  Contract.Requires<ArgumentNullException>(bar != null);

  // Something that requires non-nullness, e.g.:
  bar.Contains("test");
}

然后静态检查器抱怨Foo 正在调用FooImpl 并带有可能为空的值,并建议我将非空合约添加到Foo。好的,所以我想我不能将合同检查/异常抛出委托给实现方法。

但是如果我尝试将它放在公共界面中,即:

public void Foo(string bar)
{
  Contract.Requires<ArgumentNullException>(bar != null);

  this.FooImpl(bar);
}

private void FooImpl(string bar);
{
  bar.Contains("test");
}

然后静态检查器抱怨FooImpl 在可能为空的值上调用Contains——即使在代码中调用FooImpl 的唯一位置来自Foo,它本身确保它永远不会使用空值调用FooImpl


那么,我需要将同一份合同包含两次吗?还是我应该忽略静态检查器?我知道这是一种忙碌的工作来源,不应该依赖它,但我希望它有一些方法可以处理这种基本的、可能很常见的场景。

【问题讨论】:

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


    【解决方案1】:

    简短回答:是的。

    您应该在希望代码协定的任何地方添加先决条件,以防止出现空引用异常等情况。这有时意味着看起来您要添加两次相同的合同。

    在这种特殊情况下,很明显 FooImpl 仅从已具有前提条件的方法中调用。

    但是,静态检查器独立于其他方法评估 FooImpl 方法。 在此示例中,您只是从 Foo 传递 bar 值(您知道 bar 不是 null ),但静态检查器不确定您 没有 操作 bar,可能导致它为 null。

    此外,您应该考虑到将来您可能会从没有检查 bar 是否为空的前提条件的方法中调用 FooImpl 方法。您还希望静态检查器也能防止在这些情况下发生空引用异常。

    【讨论】:

      【解决方案2】:

      为了安抚静态检查器,我可能会在内部函数上使用 Contract.Assume(),而不是普通的 Contract 函数,所以它不会是现有合约的精确副本 - 你不想要或者在该内部函数中需要实际的运行时检查。

      至于为什么它不够聪明,无法推断出这个函数只是从另一个地方调用的,我不确定。

      【讨论】:

      • 假设添加运行时检查(取决于您选择的级别)。如果您使用“仅表面合同”,所有合同都将从内部功能中剥离。这不是 Assume 的设计目的。使用需要。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多