抛出异常与使用Contract.Requires<T>有何不同?

19

我在思考是应该抛出异常还是调用Contract.Requires<TException>

例如:

public static void Function(String str)
{
    if (str == null) throw new ArgumentNullException("str", "Input string cannot be null.");

    // ...
}

对抗

public static void Function(String str)
{
    Contract.Requires<ArgumentNullException>(str != null, "Input string cannot be null.");

    // ...
}

由于 Contract.Requires<TException> 不需要 CONTRACTS_FULL 符号,因此我也可以在发布版本中使用它。

这是我的考虑:

缺点: 无法调用定制异常类型构造函数的重载版本。 没有办法向构造函数传递其他参数。

优点: 支持静态工具(例如通知调用者违反协定)。

我应该使用哪一个,以及在什么情况下使用?


“重载异常类型构造函数”会有什么好处? - Peter Ritchie
3
我假设这是因为存在同样的构造函数。我猜是因为它提供了更多的数据/信息。 - MasterMastic
1
我不理解你关于异常类型重载的问题。此外,你可能误解了Contract.Requires<TException>的用法。如果你使用该重载,仍需要在发布版本中使用工具。如果你不使用CodeContract工具重写dll,则它不会像你期望的那样运行。 - Manuel Fahndrich
2个回答

9
在CodeContract用户指南中,if-then-throwRequires<TException>之间的基本权衡是如何使用发布版本。 情况1:仅使用if-then-throw,没有Requires<TException>。在这种情况下,您可以在未运行dll / exe上的合同工具的情况下构建发布版本。优点是构建速度更快且没有风险引入错误。第二个优点是团队成员可以选择不使用CodeContract工具。缺点是您不会得到所需的合同继承,并且您的合同不一定对工具可见(除非您使用EndContract)。您可以通过使用程序集模式:“自定义参数验证”来指定此情况。 情况2:您决定始终在发布版本上运行CodeContract工具。这使您可以使用Requires<TException>,并且您可以继承合同,包括接口的注入等。您的合同整洁且易于识别。缺点是构建您的代码的每个人都必须安装CodeContracts工具。您可以通过使用程序集模式:“Contract属性窗格中的标准”来指定此情况。
希望这些能澄清问题。

使用VS2017,有一个技巧可以让CodeContracts工具正常工作。 VS2017是否与CodeContracts兼容? - Michael Freidgeim

2
我不确定这两种方法之间是否有重大差异,但以下是我喜欢使用合同的两个原因:
1)代码更加整洁,因为您在方法顶部编写了一条语句,显示该方法基于哪些假设。您不会用违反假设的实现方法堵塞代码。
2)在编写代码时,您可以获得Visual Studio检测代码合同并提示您即将调用的方法所需的信息的好处。这有助于确保您向方法发送有效参数,而无需跳转到方法定义以检查那里的代码。
一旦代码被编译和运行,我认为没有任何重大差异。
希望这有所帮助。

1
想要增加另外两个优点。使用构建符号可以轻松地“关闭”Contracts.Requires(当您确定检查通过时)。其次(我猜Avrohom暗示的是)VS具有静态代码分析引擎,可以启用它并找到调用代码的实例,这些代码(可能)违反了合同。 - Aron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接