到目前为止,我已经做了一年的专业软件工程师,并获得了计算机科学学位。我知道c++和C中的断言有一段时间了,但直到最近才知道它们存在于c#和。net中。

我们的生产代码不包含任何断言,我的问题是这个…

我应该开始在我们的生产代码中使用断言吗?如果可以,什么时候使用它最合适?这样做会更有意义吗

Debug.Assert(val != null, "message");

or

if ( val == null )
    throw new exception("message");

当前回答

John Robbins在《调试Microsoft . net 2.0应用程序》一书中有一大节是关于断言的。他的主要观点是:

Assert liberally. You can never have too many assertions. Assertions don't replace exceptions. Exceptions cover the things your code demands; assertions cover the things it assumes. A well-written assertion can tell you not just what happened and where (like an exception), but why. An exception message can often be cryptic, requiring you to work backwards through the code to recreate the context that caused the error. An assertion can preserve the program's state at the time the error occurred. Assertions double as documentation, telling other developers what implied assumptions your code depends on. The dialog that appears when an assertion fails lets you attach a debugger to the process, so you can poke around the stack as if you had put a breakpoint there.

PS:如果你喜欢《代码完成》,我推荐你继续阅读这本书。我买这本书是为了学习如何使用WinDBG和转储文件,但前半部分包含了一些帮助避免bug的技巧。

其他回答

将Debug.Assert()放在代码中任何需要进行完整性检查以确保不变量的地方。当编译Release版本时(即没有DEBUG编译器常量),对DEBUG . assert()的调用将被删除,因此它们不会影响性能。

在调用Debug.Assert()之前仍然应该抛出异常。断言只是确保在开发过程中一切都如预期的那样。

摘自Code Complete (Wikipedia):

8 Defensive Programming 8.2 Assertions An assertion is code that’s used during development—usually a routine or macro—that allows a program to check itself as it runs. When an assertion is true, that means everything is operating as expected. When it’s false, that means it has detected an unexpected error in the code. For example, if the system assumes that a customer-information file will never have more than 50,000 records, the program might contain an assertion that the number of records is lessthan or equal to 50,000. As long as the number of records is less than or equal to 50,000, the assertion will be silent. If it encounters more than 50,000 records, however, it will loudly “assert” that there is an error in the program. Assertions are especially useful in large, complicated programs and in high reliability programs. They enable programmers to more quickly flush out mismatched interface assumptions, errors that creep in when code is modified, and so on. An assertion usually takes two arguments: a boolean expression that describes the assumption that’s supposed to be true and a message to display if it isn’t. (…) Normally, you don’t want users to see assertion messages in production code; assertions are primarily for use during development and maintenance. Assertions are normally compiled into the code at development time and compiled out of the code for production. During development, assertions flush out contradictory assumptions, unexpected conditions, bad values passed to routines, and so on. During production, they are compiled out of the code so that the assertions don’t degrade system performance.

所有的断言应该是代码,可以优化为:

Debug.Assert(true);

因为它检验的是你已经假设为真的东西。例如:

public static void ConsumeEnumeration<T>(this IEnumerable<T> source)
{
  if(source != null)
    using(var en = source.GetEnumerator())
      RunThroughEnumerator(en);
}
public static T GetFirstAndConsume<T>(this IEnumerable<T> source)
{
  if(source == null)
    throw new ArgumentNullException("source");
  using(var en = source.GetEnumerator())
  {
    if(!en.MoveNext())
      throw new InvalidOperationException("Empty sequence");
    T ret = en.Current;
    RunThroughEnumerator(en);
    return ret;
  }
}
private static void RunThroughEnumerator<T>(IEnumerator<T> en)
{
  Debug.Assert(en != null);
  while(en.MoveNext());
}

在上面,有三种不同的空参数方法。第一个接受它为允许的(它只是什么都不做)。第二个则抛出异常供调用代码处理(或不处理,导致错误消息)。第三种假设它不可能发生,并断言它是这样的。

在第一种情况下,没有问题。

在第二种情况下,调用代码有一个问题——它不应该用null调用GetFirstAndConsume,所以它会返回一个异常。

在第三种情况下,这段代码有一个问题,因为在调用它之前,它应该已经检查过en != null,所以它不是真的是一个错误。或者换句话说,它应该是理论上可以优化为Debug.Assert(true)的代码,sicne en != null应该始终为真!

仅在希望为发布版本删除检查的情况下使用断言。请记住,如果不在调试模式下编译,断言将不会触发。

对于检查为空的示例,如果这是在仅限内部的API中,我可能会使用断言。如果它在一个公共API中,我肯定会使用显式检查和抛出。

摘自《实用程序员:从熟练工到高手》

Leave Assertions Turned On There is a common misunderstanding about assertions, promulgated by the people who write compilers and language environments. It goes something like this: Assertions add some overhead to code. Because they check for things that should never happen, they'll get triggered only by a bug in the code. Once the code has been tested and shipped, they are no longer needed, and should be turned off to make the code run faster. Assertions are a debugging facility. There are two patently wrong assumptions here. First, they assume that testing finds all the bugs. In reality, for any complex program you are unlikely to test even a miniscule percentage of the permutations your code will be put through (see Ruthless Testing). Second, the optimists are forgetting that your program runs in a dangerous world. During testing, rats probably won't gnaw through a communications cable, someone playing a game won't exhaust memory, and log files won't fill the hard drive. These things might happen when your program runs in a production environment. Your first line of defense is checking for any possible error, and your second is using assertions to try to detect those you've missed. Turning off assertions when you deliver a program to production is like crossing a high wire without a net because you once made it across in practice. There's dramatic value, but it's hard to get life insurance. Even if you do have performance issues, turn off only those assertions that really hit you.