写一段时间的程序,总是感觉开发过程中大部分的时间都花在了调试代码上,而不是实现功能。所以上网找了一下,如何尽早地发现Bug,提高软件质量的文章。看到了断言技术,感觉断言是每个程序员必备的基本功。可以让程序中的Bug在离其发生地最近的地方被断言发现,防止Bug的蔓延。
  在.NET中的断言的使用,是使用System.Dig.Debug。断言一般是在程序处于Debug模式下,才起作用。而可以在程序发布时(即Release模式),编译器会采用条件编译,将断言从Release版本的dll中去掉。
  该使用断言几种使用场景,如:
1、方法参数的合法性
2、对于非法情况进行断言而对于错误情况不断言且必须处理
3、对于任何假定进行断言
4、用断言对程序开发环境(OS/Compiler/Hardware )的假设进行检查
5、编写防错程序,然后在处理错误之后可用断言宣布发生错误(一般对于Switch语句中的default进行断言)
6、用断言保证没有定义的特性或功能不被使用(如果原先规定的一部分功能尚未实现,应进行断言)。
  这些断言的使用场景,我都同意。不过,我有以下几个疑问:
1、对于第一条,由于断言会在程序的Release版本中由编译器自动去掉,那么往往我们开发一个基本库,public、protected修饰的方法怎么能保证调用者输入的参数的合法性呢(当然如果是调用者使用的是Debug版本的程序那是没有什么问题)。
2、我们将程序发布给用户,即使我们在开发过程中使用了断言,可以大大提高程序的质量,但是难免程序中仍然有Bug。那么用户在使用Release版本的程序时,如果程序出现Bug,我们怎么才能像调试阶段一样,在离Bug出生地最近的地方,发现它呢?我目前,只认为可以将程序出现的异常,在程序的最上层,捕获所有的异常,并将异常信息及堆栈信息作为日志保存下来。但是这个时候,我们还是难以定位这个Bug,因为其出生地已经难以定位了。
  上面是我的一些疑问,还请各位指教讨论。对于什么时候该用断言,什么时候不应该用断言,还请各位也讨论一下。

解决方案 »

  1.   

    ref:
    http://blog.csdn.net/Knight94/archive/2006/06/18/809479.aspx
      

  2.   

    谢谢指教,不过你发的文章只是讲了如果使用条件编译,来实现在Debug模式下,打印调试信息,而是Release中不打印。还没回答,我提的两个疑问。
    请问一下,你在编码中是如何使用Debug.Assert的
      

  3.   

    不应该将断言从Release中去掉,除非对效率影响很大(其实大部分情况影响不大).
      

  4.   

    那你的意思就是说使用Trace.Assert这种断言吗?我也一直对该该去掉断言,拿不定主意。
      

  5.   

    对于internal、private,那当然是应该用断言。对于public或是protected的方法的参数验证,是否应该用断言呢?to brightheroes(在地狱中仰望天堂) :
    那是不是对每个断言的地方,用一个Log来替代呢?我对于什么时候该用Log,不是很有把握。有没有一个统一的解决方案呢?
      

  6.   

    to lintw
    我一般就在异常catch的时候放Log。或者重要操作的时候。
      

  7.   

    对于internal、private,那当然是应该用断言。对于public或是protected的方法的参数验证,是否应该用断言呢?
    对于这一点还请各位指教
      

  8.   

    基本上对于public的函数的传入参数我使用断言检查,不符合的话就让程序退出。不过,断言确实不应该过多出现给用户。因为几乎所有出现断言的地方,程序都应该立即退出。这和异常的情况完全不同。关于Debug和Trace的讨论,推荐这篇文章,十分详尽。http://www.codeproject.com/csharp/DebugTreatise.asp
    当然,希望你英语足够好。
      

  9.   

    to lextm:
    那你使用的断言检查不会是Debug.Assert吧。因为如果用了Debug.Assert的话,当你以Release模式发布程序后,这些断言将不起作用。
      

  10.   

    我从来不用断言,我认为断言是以前c程序员的陋习。现在,没必要为了那一点点“运行时效率”去避免使用“if(...) Throw ...”的控制方法。如果要我使用断言,我就会问:“如何证明断言可以在release时肯定都是多余的?”
      

  11.   

    看样子贴主没有把“断言”这个概念弄清楚。断言在《.Net 和 Windows 应用程序调试》(Debugging Application for Microsoft(R) .NET and Microsoft Windows)这本微软黑皮书里说的非常清楚。以下是引用里面的原话(第三章 边编码边调试 P68):
    “断言是一些只在调试版本才会被执行的函数或宏,他们会通过消息对话框提示哪些条件失败了。”也就是说,断言是以前C/C++开发中,没有异常这个概念,也没有像VS.net那样的高级开发环境中,程序员使用的一种调试辅助工具。即当项目比较大且多人开发时,断言在开发过程中就起到很大的作用了,在项目开发的几个过程,即添加新功能(新代码)时期,单个库测试时期,联合测试时期等,在这几种开发里程碑里,添加新功能时期尤其需要断言,它是当时唯一能够检测出内部的参数传递错误以及调用错误时进行必要的处理的功能。.Net中的断言同样不需要再Release时使用,因为贴主的问题是程序发布后进行参数检查,这时断言已经不需要了,因为检查客户输入是表示层代码的重要人物之一,否则.net也不会有WebForm/WinForm下的许多验证控件了。表示层的功能就是显示程序界面,接受用户的输入,进行验证,调用必要的代码进行处理并向用户提供反馈。我的意见是,只要是public/protected等公开的类方法,必须进行参数验证,验证失败抛出ArgumentException系列的异常。贴主如果要监视Release下客户端异常报告,那么只能用log文件,网上有很多(包括微软)这样的帮助库,可以去搜索并下载。
      

  12.   

    就我个人感觉,断言是与异常不一样的东西,断言是来验证必然性的事情(绝不允许发生),而异常则是在程序发布给用户后,有可能发生的情况。
        所以我想对于public/protected的对外公布的方法,我们难以甚至于没法保证,这些方法的输入参数的正确性,所以也符合异常的使用场景——有可能发生,无法控制的情况。所以得用抛出异常的方式来处理public/protected的输入参数的验证。这一点,我是很赞同TomMax(笑望人生) 的说法。
        但是我也同样存在这样的疑问,如sp1234“如何证明断言可以在release时肯定都是多余的?”。的确,这种事情真的很难决定说,哪些断言应该去掉。
        我想,如果Release版本的断言如果去掉,那么当程序出现了异常,即使我捕获了全局的unhandlerException异常,并用日志记录了异常信息及堆栈信息,但是由于没有断言,我仍然是很难根据异常信息来发现Bug,并解决它。
        所以我就想,难道assert就真的如同sp1234(对 DLinq 架构颇为失望) 所说的,断言是c/c++的东西,在dotnet环境下编程,不应该用吗?我想存在就是合理,.net下为什么要有Debug.Assert这样的断言方法呢?
        真的,我有点胡涂了。还请各位,多多讨论。可以不要局限于断言,大家可以谈谈,如果在开发阶段,如果减少bug,提高开发效率、提升开发质量。
      

  13.   

    to myminimouse:你是指nunit中的assert来替代Debug.Assert吗?那实际上nunit中的assert和debug.assert差不多,只不过多了一些断言,不当当只是istrue。
    而且assert只是简单地抛出异常,并没有条件编译,即不可以在Release中去掉。
    不过,还请问你是怎么使用nunit中的assert中类的方法级内部进行断言的。我们一般都只是用nunit来对方法进行黑箱测试,即单元测试。
      

  14.   

    《代码大全2》中指出
    在永远不可能发生错误的地方使用断言。我的理解,比如说一个private方法中的string参数,传进来的时候不能为空。
    在可能出错,程序应当处理的地方使用异常--我的理解,比如说调用一个远程服务器上的WebService,极有可能远程主机不可达,这时要用异常。