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

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

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

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

or

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

当前回答

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

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.

其他回答

就其价值而言……我发现我的公共方法倾向于使用if () {throw;}模式,以确保方法被正确调用。我的私有方法倾向于使用Debug.Assert()。

The idea is that with my private methods, I'm the one under control, so if I start calling one of my own private methods with parameters that are incorrect, then I've broken my own assumption somewhere--I should have never gotten into that state. In production, these private asserts should ideally be unnecessary work since I am supposed to be keeping my internal state valid and consistent. Contrast with parameters given to public methods, which could be called by anyone at runtime: I still need to enforce parameter constraints there by throwing exceptions.

此外,如果某些东西在运行时不起作用(网络错误、数据访问错误、从第三方服务检索的坏数据等),我的私有方法仍然可以抛出异常。我的断言只是为了确保我没有破坏我自己关于对象状态的内部假设。

根据设计标准,你应该

坚持每一个假设。平均每五行就有一个断言。

using System.Diagnostics;

object GetObject()
{...}

object someObject = GetObject();
Debug.Assert(someObject != null);

作为一个免责声明,我应该提到我还没有发现实现这个IRL是实际的。但这是他们的标准。

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

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应该始终为真!

我不会在产品代码中使用它们。抛出异常,捕获和记录。

在asp.net中也需要小心,因为断言可以显示在控制台上并冻结请求。

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

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