假设我有一个方法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/