Debug.Assert与特定的抛出异常

Nij*_*Nij 33 c# assert exception-handling

我刚刚开始浏览John Robbins的"调试MS .Net 2.0应用程序",并且因为他对Debug.Assert(...)的传福音而感到困惑.

他指出,良好实现的Asserts会在某种程度上存储错误状态,例如:

Debug.Assert(i > 3, "i > 3", "This means I got a bad parameter");
Run Code Online (Sandbox Code Playgroud)

现在,就个人而言,我似乎很疯狂,他如此喜欢在没有真正明智的"商业逻辑"评论的情况下重述他的测试,也许"因为flobittyjam widgitification过程,我必须永远不会发生i <= 3".

所以,我认为我认为Asserts是一种低级别的"让我保护我的假设"的东西......假设一个人认为这是一个只需要在调试中做的测试 - 即你保护自己不受同事的影响和未来的程序员,并希望他们实际测试的东西.

但是我没有得到的是,他继续说除了正常的错误处理之外你还应该使用断言; 现在我设想的是这样的:

Debug.Assert(i > 3, "i must be greater than 3 because of the flibbity widgit status");
if (i <= 3)
{
    throw new ArgumentOutOfRangeException("i", "i must be > 3 because... i=" + i.ToString());
}
Run Code Online (Sandbox Code Playgroud)

我通过Debug.Assert重复错误条件测试获得了什么?如果我们谈论一个非常重要的计算的仅调试双重检查,我想我会得到它...

double interestAmount = loan.GetInterest();
Debug.Assert(debugInterestDoubleCheck(loan) == interestAmount, "Mismatch on interest calc");
Run Code Online (Sandbox Code Playgroud)

...但是我没有得到参数测试,这肯定值得检查(在DEBUG和Release版本中)......或者不是.我错过了什么?

Chr*_*ung 48

断言不适用于参数检查.应始终进行参数检查(并且精确地根据文档和/或规范中指定的前提条件),并ArgumentOutOfRangeException根据需要进行抛出.

断言用于测试"不可能"的情况,即(在程序逻辑中)假设的事情是真的.断言是告诉你这些假设是否因任何原因被破坏.

希望这可以帮助!

  • 断言可用于*internal*方法调用的参数检查(由属于同一组件的代码调用)方法,而不是外部方法调用(由另一个组件调用).例如,我可能断言Double类型的私有方法参数不是NaN. (10认同)
  • 别担心我发现了原因.根据Jon Skeet的说法,http://stackoverflow.com/questions/1276308/exception-vs-assertion:"在代码中使用断言进行内部逻辑检查,并在正确的代码控制之外使用错误条件的正常异常." (7认同)

hwi*_*ers 17

断言与异常抛出有沟通方面.

假设我们有一个带有Name属性和ToString方法的User类.

如果ToString是这样实现的:

public string ToString()
{
     Debug.Assert(Name != null);
     return Name;
}
Run Code Online (Sandbox Code Playgroud)

它表示Name应该永远不会为null,如果是,则User类中存在错误.

如果ToString是这样实现的:

public string ToString()
{
     if ( Name == null )
     {
          throw new InvalidOperationException("Name is null");
     }

     return Name;
}
Run Code Online (Sandbox Code Playgroud)

它表示如果Name为null,调用者正在使用ToString,并且应该在调用之前检查它.

两者的实施

public string ToString()
{
     Debug.Assert(Name != null);
     if ( Name == null )
     {
          throw new InvalidOperationException("Name is null");
     }

     return Name;
}
Run Code Online (Sandbox Code Playgroud)

如果Name为null,那么User类中会出现bug,但我们还是要处理它.(用户在打电话之前不需要检查姓名.)我认为这是罗宾斯推荐的那种安全措施.


Mar*_*son 5

在提供关于测试问题的调试与断言的指导时,我已经考虑过这个漫长而艰难的过程.

您应该能够使用错误的输入,错误的状态,无效的操作顺序以及任何其他可能的错误条件来测试您的类,并且断言永远不会跳闸.每个断言都在检查一些事情应该始终为真,无论输入或计算是什么.

我已经达到了良好的经验法则:

  1. 断言不能替代能够正确独立于配置运行的健壮代码.它们是互补的.

  2. 在单元测试运行期间,即使在输入无效值或测试错误条件时,断言也不应跳闸.代码应该处理这些条件而不会发生断言.

  3. 如果断言跳闸(在单元测试中或在测试期间),则会对该类进行窃听.

对于所有其他错误 - 通常是环境(网络连接丢失)或误用(调用者传递空值) - 使用硬检查和异常会更好,更容易理解.如果发生异常,则调用者知道它可能是他们的错.如果发生断言,则调用者知道它可能是断言所在代码中的错误.

关于重复:我同意.我不明白为什么你会用Debug.Assert和异常检查来复制验证.它不仅会给代码增加一些噪音,而且还会让人感到困惑,因为这是一种重复的形式.