2010-12-15 86 views
17

关闭我的头顶,我能想到的4种方式检查null参数:测试前提条件的不同方法的优缺点?

Debug.Assert(context != null); 
Contract.Assert(context != null); 
Contract.Requires(context != null); 
if (context == null) throw new ArgumentNullException("context"); 

我一直使用的最后一个方法,但我刚才看到的代码片段使用Contract.Requires,我不熟悉。 每种方法的优缺点是什么?有其他方法吗?


在VS2010 W/ReSharper的,

  • Contract.Assert警告我说,表达始终是真实的(它是如何知道的,我不太清楚......不能HttpContext的为空? ),
  • Contract.Requires被淡化了,它告诉我的编译器不会调用的方法(我假设,因为前者的原因,它永远不会为空),并
  • 如果我改变的最后选择context != null所有代码如下翅膀渐渐消失,它告诉我代码是启发式无法达到的。

因此,看起来最后3种方法有一些内置到VS静态检查器中的智能,而Debug.Assert是愚蠢的。

+0

问题不明确。你是否真的试图一次全部使用它们? – 2010-12-15 01:22:59

+0

@Matthew:不知道这怎么不清楚......不,我没有试图一次性使用它们。我做了一个类似的代码片段来说明你可以检查null的不同方式。 – mpen 2010-12-15 02:59:22

+0

这就是我从问题的其余部分想到的,但是你使用的语法呈现很奇怪。 – 2010-12-15 03:06:00

回答

12

我的猜测是有一个合约适用于接口IHttpHandler.ProcessRequest,它要求上下文!= null。接口契约由其实现者继承,所以你不需要重复需求。事实上,您不能添加额外的Requires语句,因为您仅限于与界面合同相关的要求。

我认为区分指定合同义务和简单执行空检查很重要。您可以在运行时实施空检查并引发异常,以通知开发人员他们正在正确使用您的API。另一方面,契约表达式实际上是一种元数据形式,它可以由合约重写器来解释(以引入之前手动实施的运行时异常),也可以由静态分析器来解释,它可以用它们来推理了解您的应用程序的静态正确性。这就是说,如果你正在一个你正在积极使用代码契约和静态分析的环境中工作,那么最好把断言放在契约形式中,以便利用静态分析。即使您没有使用静态分析,您仍然可以通过使用合约为以后的利益敞开大门。需要注意的主要问题是您是否配置了项目来执行重写,否则合约不会像您期望的那样导致运行时异常。


要在阐述什么评论者说,断言之间的差,假设和要求是:

  • 甲Contract.Assert表达式被转换成由所述合同重写和静态分析器的断言试图根据其现有证据来证明这一表达。如果它不能被证明,你会得到一个静态分析警告。
  • Contract.Assume表达式被合约重写器忽略(据我所知),但被静态分析器解释为它在静态分析中可以考虑的新证据。合同。假设习惯于在静态分析中“填补空白”,无论是缺乏进行必要推理的复杂性还是与尚未用合同进行过修饰的代码进行交互操作时,都可以假设,例如,一个特定的函数调用返回一个非空结果。
  • Contract.Requires是调用方法时必须始终为真的条件。它们可以是对方法参数的约束(这是最典型的),它们也可能是对象的公开可见状态的约束(例如,如果Initialized为True,则只允许调用该方法)。这些类型的约束推动你的类的用户在使用对象时检查初始化(如果不是,则可能会适当地处理错误),或者创建他们自己的约束和/或类不变量来澄清初始化确实发生了。
+0

那么......那么Contract'Assert'和'Contract.Requires'之间的区别究竟是什么? – mpen 2010-12-15 03:05:34

+2

@Ralph:'Contract.Requires'表示在调用该方法时应该为true的事物,'Contract.Assert'应该在您的方法中间检查中间状态。在正确的位置添加'Contract.Assert'可以帮助静态分析器验证您的代码是否正确,如果它无法自行管理的话。 – 2010-12-15 03:18:28

+3

实际上,静态检查器只会从Contract.Assume中受益。此方法在运行时的行为与Contract.Assert相似,但告诉静态检查器不要试图统计证明这一点。 – koenmetsu 2010-12-15 07:53:50

2

第一种方法适用于测试不应存在的空条件。也就是说,在开发过程中使用它来确保它不会意外地被设置为null。由于它不做任何错误处理,因此这不适用于处理发布产品中的空条件。

我会说第二和第三个版本是相似的,他们不以任何方式处理这个问题。

通常,如果变量在最终产品中可能实际上为空,则最后一个版本是可以使用的版本。你可以在那里做特殊的处理,或者像你一样引发异常。

+1

实际上,第二个和第三个方法使用静态分析来试图在编译时证明它们是真实的。 – 2010-12-15 01:33:24

+0

@Anon:但是静态分析器将无法在编译时捕获所有空例外......如果一个人滑倒,会发生什么?它是否会引发异常,崩溃,什么都不做或什么? – mpen 2010-12-15 03:03:55

+1

@Ralph:如果静态分析器无法证明任何方式(它不能证明合约在某些情况下会失败,但它不能证明它总是正确的),它会显示编译警告(不是错误)并将其替换为断言。 – 2010-12-15 03:19:09