假设我有一个方法public void Foo(string bar),调用者不应使用空值bar进行调用。假设我还有一个方法称为private void FooImpl(string bar),它可以完成Foo的实际工作。当然,即使FooImpl是公共接口,bar确实需要Foo不为空。可以说,我想使用.NET 4.0代码协定来强制执行此非null。

我将合同放在哪里?

如果我这样做:

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



因此,我需要两次包含同一份合同吗?还是我应该忽略静态检查器?我知道这是一种忙碌的资源,不应该依赖它,但是我希望它有某种方式可以处理这种基本的,大概是常见的情况。

最佳答案

简短的回答:是的。

您应该在希望使用代码协定的任何地方添加前提条件,以防止出现诸如nullreference异常之类的事情。有时这意味着您看起来好像两次添加相同的合同。

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

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

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

关于c# - .NET 4代码契约(Contract):我是否需要两次包含相同的契约(Contract)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3141025/

10-11 17:21