【问题标题】:What is a post-condition exception?什么是后置条件异常?
【发布时间】:2014-06-28 16:37:44
【问题描述】:

我正在做一些有问题的作业:

你会如何处理前置条件异常?
您将如何使用后置条件异常?

所以对于第一个问题,我假设前提条件是必须满足的条件才能使函数运行。例如,参数不能为空,我们可以抛出异常:

if (myArg == null)
    throw new ArgumentNullException("myArg");
//do work here

但是,我不知道后置条件异常的用途是什么,以及为什么我们要在这种情况下抛出异常(例如,如果不满足条件而不是返回 false)。

任何人都可以为此提供一个例子吗?

【问题讨论】:

  • C# 没有本机前置/后置条件 - 但是,请参阅 Code Contracts:“代码协定提供了一种在代码中指定前置条件、后置条件和对象不变量的方法。前置条件是必须进入方法或属性时满足。后置条件描述方法或属性代码退出时的预期。对象不变量描述处于良好状态的类的预期状态。"
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • 至于“为什么”,我认为从像 Eiffel 这样的语言的角度来看,这是最根深蒂固的:ET: Design by Contract (tm), Assertions and Exceptions(作者 Bertrand Meyer 写了几篇论文并就该主题进行了教学.)
  • 我从未听说过“后置条件异常”这个词。你从哪儿弄来的? “后置条件”是业内常用的术语。

标签: c# exception conditional-statements post-conditions


【解决方案1】:

后置条件是一段代码(例如方法或函数)在函数退出时给出状态的保证,例如返回值的正确性,或者更广泛的状态的正确性,例如作为类实例甚至整个程序的状态。

我会将Post-Condition Exception 解释为引发异常的操作(直接使用throw,或使用保护Assert),而不是简单地返回失败的返回码或默认值,调用者可能不会检查。

硬故障在检查前置条件、后置条件和不变量时至关重要,作为软返回(例如像 false0-1) 需要由调用者检查(并且可能会被忽略)并掩盖代码在设计外状态下运行的真正问题 em>

以下示例希望说明使用异常的后置条件。在我对Square(x) 的简单设计中,只要输入的合同有效(即输入数字的平方不会溢出),该函数应该保证结果是一个正数。如果后置条件检查失败,则意味着我的设计/实现中存在缺陷,这可能会产生可怕的后果(例如,没有想到的场景,或依赖项失败,例如在 Math 库本身中)。

例外示例:

public static double Square(double number)
{
   // Pre condition
   if (Math.Abs(number) > Math.Sqrt(double.MaxValue))
       throw new InvalidArgumentException("Number too big - will overflow");

   var result = number * number;
   // Post condition
   if (result < 0)
       throw new Exception("Square(x) should always be positive!");
   return result;
}

根据 cmets,Code Contracts 还允许通过 Contract.Ensures 指定后置条件。这样做的好处是,前置条件和后置条件都记录在方法的顶部,并且还避免了对额外局部变量的需要,因为可以直接“检查”结果:

public static double Square(double number)
{
   Contract.Requires(Math.Abs(number) < Math.Sqrt(double.MaxValue), 
      "Oops number will result in overflow");
   Contract.Ensures(Contract.Result<double>() >= 0, 
      "Square should always be positive!");

   return number * number;
}

代码合约相对于基于异常的断言的另一个优势是static checking- 合约可以在编译后验证。

【讨论】:

    【解决方案2】:

    另一个答案是正确的,cmets 在回答您的问题时都很有用。我觉得还有一点可以补充的,所以这是我的贡献。

    我也从未听说过它被称为“后置条件异常”,但至于你的问题,“什么时候使用它们”,它们在单元测试中被大量使用(参见 https://stackoverflow.com/tags/unit-testing/info 或其他资源,如维基百科-到)。在单元测试中,测试程序员调用她想要测试的函数,并且她还知道她期望从函数中得到什么值(即,从其他知识来源知道的正确答案)。后置条件测试是:“函数或方法返回的期望值和实际值是否一致?”

    然后,如果他们不同意,Assert 方法会抛出异常。测试框架软件捕获异常,然后将给定的测试报告为失败,然后继续运行其他测试,而不会在失败的测试上停止。这是一个玩具示例来说明。

    [TestMethod]
    public void Integers_7Add1_equals8()
    {
       int expected = 8;
       int actual = MyClass.AddOne(7);
       Assert.AreEqual(expected, actual);
    }
    

    所以异常是在Assert.AreEqual方法调用中,调用被测方法后抛出的,属于后置条件异常。

    【讨论】:

    • 好答案,这可能是我们在课堂上进行单元测试后出现异常的原因之一——我只是不认为 Assert.AreEqual() 是后置条件异常,但是当你想到它时,这基本上就是它正在做的事情。谢谢。 +1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    相关资源
    最近更新 更多