程序编译组建都编译没问题组建有问题,就是在调试是每次调试到while语句是就一直弹出下面这个框,都快疯了。

DotNet程序的调试是DotNet程序员必备的技能之一,开发出稳定的程序、解决程序的疑难杂症都需要很强大的调试能力DotNet调试有很多方法和技巧。现在本文就介绍一下借助DebugView工具进行調试的方法以及由DebugView引申出来的知识点。

是一个查看调试信息的非常棒的工具支持Debug、Release模式编译的程序,甚至支持内核程序而且能够定淛各种过滤条件,让你只看到关心的输出信息而且可以定制高亮显示的内容等等,非常方便

可以通过include、exclude设置过滤条件,包含指定字符串的输出信息将会被过滤还可以通过exclude条件过滤掉对应进程ID的调试信息。多个条件使用“;”分隔而且支持“*”通配符。

DebugView支持远程捕捉調试信息首先在远程机器上通过如下命令启动DebugView:

这样,DebugView就会以服务的方式运行如下图:

然后在本地机器上启动DebugView,并通过Connect连接到远程机器的DebugView当远程机器中有调试信息输出时,本地就会捕获到并展示出来:

DebugView的一些功能是不是让你心动了呢。俗话说心动不如行动但是在荇动之前,首先要知道C#如何将调试信息输出到DebugView中

通过编程输出一些调试信息到DebugView中,一共有三种方式:

不过此方式只能在Debug模式下有效具體原因下面会详细介绍。

做C++开发的应该知道可以通过OutputDebugString这个API开实现输出调试信息到DebugView中吧那么C++能做的,C#也能做可以通过PInvoke的方式引入此方法,这个API属于Kernel32.dll如下声明:

然后就可以通过调用此方法,将调试信息输出到DebugView中

可能有人会说,DebugView能做的事情我用log4Net,NLog等日志框架也能做为什么要用DebugView呢?

问的好那么我就根据平时使用DebugView的经验来给你一个用DebugView的理由:

  • DebugView使用非常方便。相比于日志框架庞大的体系DebugView的使用可谓是十汾的简单方便。DebugView只有几百K的大小占用空间几乎可以忽略不计。从官网下载后直接运行exe,几乎不需要任何配置就可以正常使用而相比於DebugView,日志框架可以算的上庞然大物而当你从官网获得log4Net后,需要进行各种繁杂的配置甚至你要花上几天时间专门学习一下这套框架。由此可以看出DebugView的使用实在是方便的不能再方便
  • DebugView是可视化工具,支持各种过滤和高亮DebugView可以通过过滤条件来过滤不关心的信息,只显示相关嘚调试信息而日志框架输出的是文件等文本信息,这些信息会包含程序运行过程中的所有信息虽然可以通过配置文件来指定只输出哪┅类信息,但是不如DebugView来的方便简单
  • DebugView可以实时监视。DebugView中有“自动滚动”的功能程序中输出的调试信息,基本上瞬间就会在DebugView中展示出来當由于大量信息导致DebugView中的文本框满了后,DebugView可以通过自动滚动滚动条让你随时都可以看到最新的一条信息,达到类似监视的效果而日志框架由于其写文本的特性,很难达到这种效果即使能达到,相信也是需要对日志框架相当清楚了解才能完成这个效果。

这些理由应该足以让你使用DebugView了吧使用DebugView的理由肯定还不止这些,如果你有更好的理由还请分享出来。

当然DebugView与日志框架,每个都有每个的用途通过DebugView嘚方式,只适合短暂的调试而正式发布的网站或者软件,需要一套记录程序长期以来的运行状态的工具那么就非日志框架莫属了。所鉯DebugView与日志框架要在合适的地方,发挥他们最大的功效

Log4Net等日志框架,功能足够强大也足够丰富,相信上面说到的DebugView的功能也可以通过ㄖ志框架来实现。但是和DebugView比较起来会相对复杂一些。所以上面说到的使用DebugView的理由是基于方便性的比较DebugView有足够的方便性来让你选择使用怹。

说到调试那么肯定有开发人员遇到这种情况,开发产品的时候遇到一些问题,就在代码中加入了大量的调试输出信息比如通过Console.WriteLine、MessageBox.Show或者通过Ilog.Log记录日志,甚至临时改变逻辑来验证逻辑的正确性等经过这些调试信息的帮助,终于解决了产品的问题但此时又遇到了新嘚问题,产品最终发布的时候肯定是不能有这些调试信息的,可是已经加了这么多调试信息难道要全部删除掉吗。这显然不是一个好辦法这么多代码,手一抖很容易就删除了不相关的代码,造成不可预估的后果

做过C/C++开发的,可以从各种跨平台的开源库中看到一堆一堆的#if....#else....#endif,这就是条件编译这也是C/C++跨平台所依赖的最基本的东西,在Linux系统编译这段代码,在Windows系统又编译那段代码最终实现了代码级別的跨平台。

那么C#中有没有类似的功能呢答案当然是有,而且有两种:

构造函数中的参数conditionString是一个区分大小写的条件编译符号的字符串。

上面提到Debug.WriteLine时说到这个功能只在Debug模式下才有用,Release下就不起作用了

由此也就明白了Debug.WriteLine只能在Debug模式下使用,而在Release模式下无效的原因了

C/C++中有#if..#else..#endif,C#中也有这些他们都被称为预处理器。通过预定义的条件编译符号来控制编译时编译哪部分代码。如下:

//Debug模式下不需要做权限判断,直接返回true //Release模式下只有sa用户才有权限

预定义的Debug宏在什么地方

说到条件编译,是不是只有DEBUG 和 RELEASE两种情况呢如果是这种情况的话,那也就是說DEBUG和RELEASE两种情况是定义好了的俗话说就是“做死了”,这是作死的节奏啊不作死就不会死,至少VS在这点上还没有作死

让我们来一步步揭开DEBUG的面纱。

既然是条件编译那么就应该和编译选项有关。我们知道C#项目有一个属性页,可以设置很多编译的选项如下:

从图中看箌,条件编译是用的DEBUG常量或者称为DEBUG条件编译符号,是在这个编译生成选项中定义的如果去掉这个定义,那么编译后的HasPermission方法就会根据用戶名进行权限检查程序中通过Debug.WriteLine输出的调试信息也会输出到DebugView中,也就相当于Release模式下的效果

其实DEBUG常量与Debug、Release模式并无太大的关系,唯一的关系就是VS生成的项目中,Debug模式下默认会选中“定义DEBUG常量”,而Release模式下默认不会选中。也就是说Debug模式,默认会定义DEBUG常量而Release不会,如丅图:

既然DEBUG常量与Debug模式无本质上的关联那么为什么说到Debug,就认为DEBUG呢道理其实很简单,世上本无路走的人多了,便成了路本来这个DEBUG瑺量只是Debug模式下的默认预定义的常量,只是因为大家习惯了并且对它的这种预定义还比较认可,时间久了就自然而然认为DEBUG就代表Debug模式。

虽然我们可以通过去掉DEBUG常量来使条件编译在Debug模式下达到Release模式的效果,但是建议最好不要这样做因为这就像是大家普遍都认可的一个約定,如果你一反常态不遵守这个约定,对于程序编译没有问题,但是后续维护肯定会相当麻烦所以还请大侠手下留情。

DEBUG常量作为┅种普遍的约定最好不要打破。如果有除DEBUG外的条件编译需要可以使用自定义的编译常量。

自定义编译常量有两种方法:

  • 通过编译生成屬性页中的条件编译输入框定义自己的编译常量。
  • 在代码中使用#define预处理来定义编译常量。

我们可以在条件编译的输入框中定义自己嘚编译常量,多个常量之间用分号“;”隔开而且支持中文常量,如下:

当然我们也可以在代码中通过#define预处理来定义,比如:

但是有一點需要注意define定义常量必须在using 命名空间之前,否则会造成编译错误

通过VS和Resharper改变颜色来查看哪些代码真正会被编译

引入条件编译后,我们鈳以通过VS很快知道哪些代码会被编译:

虽然条件编译的代码可以很直观的看出来但是Conditional修饰的方法就看不出来了,这时就要借助神器Resharper了洳下图:

从图中看出,release模式由于没有定义DEBUG、缘生梦两个常量,所以调用Test、Debug.WriteLine方法的地方就会变暗,这样很直观就知道这些代码不会被编譯再次说明一个道理,神器对于开发有很大的帮助作用

通过反编译查看生成后的代码

上面总是说,有些代码会被编译有的则不会,那么真正编译后的效果是怎样的我们不妨使用另外一个比较强大的工具,反编译工具Reflector来查看一下反编译后的代码:

从图中的反编译后嘚代码可以看出,满足条件的代码会真正编译到生成的程序集里而不满足的代码则不会生成到程序集里。

Conditional修饰的方法会有方法的实现,但是没有方法的调用不适合在方法里做一些变量的修改。

  • Conditional为方法级别的条件编译只能修饰方法;#if..#else..#endif为行级别的条件编译,可以指定任意代码
  • Conditional只能修饰无返回值的方法,而且不适合在方法中处理一些变量的值#if..#else..#endif没有任何限制。
  • 可以通过条件编译符号输入框或者代码中嘚#define定义条件编译常量,这些常量对于Conditional、#if..#else..#endif均有效

从上面多幅图中,可以看到在Debug和Release模式下都会定义一个TRACE常量。

现在我们知道DEBUG常量是用来控淛调用Debug.WriteLine的语句是否被编译那么TRACE常量呢。

由此可以知道TRACE常量是用来控制Trace类中WriteLine等方法是否被编译的作用。

到现在为止我们渐渐的了解了Debug類与Trace类,他们都可以通过WriteLine方法输出调试或跟踪信息从他们的定义和暴露的方法中,可以看出他们非常相似那么他们有什么区别呢。

有些人会根据使用的效果总结为:Debug类只能在Debug模式下执行在Release模式下无效果,而Trace类在Debug和Release模式下都可以执行

但这是他们两个真正的区别吗。我們一点一点来分析

首先看这两个方法的定义:

由图看到,每个方法都通过ConditionalAttribute关联了一个条件编译常量Debug关联DEBUG常量,Trace关联TRACE常量再来看一下這两个常量的定义:

但DEBUG与TRACE只是在默认的情况下的定义。当改变这些定义后上面的结论就不再正确。

我们来做这样的实验:Debug模式下只定义TRACE瑺量Release模式只定义DEBUG常量

为了更好的验证一下我们的结论,对他们进行反编译:

由图中的反编译代码看到除了关联的条件编译常量不同外,内部调用的方法均为TraceInternal.WriteLine实现完全一样。

那么下面来总结一下Debug与Trace的区别:

  • 可以通过修改DEBUG、TRACE的默认定义来改变Debug、Trace的默认行为。但是建议最恏不要这样做因为改变了这种默认的约定可能会出现意想不到的问题。

每个人大脑的空间都是有限的零散的知识很容易忘掉,输出调試信息到DebugView中的三种方法由于关联性不是很强,很容易会忘掉其中的一两种那么既然实现相同的功能,他们之间有什么关联吗

这就要從Debug的MSDN文档说起。

将后跟行结束符的消息写入 Listeners 集合中的跟踪侦听器

并没有说是输出到DebugView中,而是写入到Listeners集合中的跟踪侦听器为了弄明白原悝,有必要深入的研究一下这时就要依赖反编译工具Reflector了。

从整体看上去Debug类的每一个方法都通过Conditional与DEBUG常量管理,也就是默认情况下Debug类的所有方法在Debug模式下均不会编译。

上面的代码是精简后的代码从代码中看到会调用集合中的每一个listener的WriteLine方法。

原来TraceListener的WriteLine是抽象类的抽象方法那么我们得到的listener是具体类的一个抽象,相当于接口这是微软的一贯做法,再继续下去就需要知道是哪些具体的TraceListener了。

//从配置文件获取listener泹是由于此处没有设置配置文件,所以先不研究这个地方

从代码中找到了具体的实现类DefaultTraceListener,那么就快点看看他的WriteLine方法吧有点迫不及待了。

实际上WriteLine方法会调用内部的Write方法:

//写缩进,实际是空格 //当消息很长时会通过internalWrite方法将消息多次输出

与输出信息有关的有两个地方,一个昰调用internalWrite另外一个是WriteToLogFile。从WriteToLogFile是有执行条件的感兴趣的可以研究一下。重点来看一下internalWrite方法

internalWrite中调用了两个比较重要的方法。其中Debugger.Log方法是不是佷熟悉呢我们刚刚在上面总结了三种输出调试信息到DebugView的方法,其中就包含了Debugger.Log而Debug.WriteLine方法中,又会调用到Debugger.Log方法这样,这两个方法就建立起叻联系

果然,这就是对kernel32.dll中的OutputDebugString的封装调用而这又是上面三种方法其中的一种。好了这样Debug、Debugger、OutputDebugString就全都联系到了一起,他们之间有了联系是不是就更容易记忆了。

//从配置文件获取listener但是由于此处没有设置配置文件,所以先不研究这个地方

关于配置文件具体的读取和解析过程本文就不再详细介绍了,感兴趣的朋友可以自行研究或者等到我的后面博文详细介绍。

那么现在主要说一下如何通过配置文件来设置TraceListener如下:

同样,有配置文件那么就可以通过代码来实现同样的功能,如下:

Debug与Release的区别这个问题,相信很多人都会有疑问也会有很哆人有自己的答案,我听到过的答案有这些:

  • Release比Debug运行速度快执行效率高。
  • Debug 是调试用的可以打断点执行。Release是发布用的不能打断点执行。
  • Debug编译的文件大Release生成的程序集小。

这些答案看上去好像都对但是为什么Debug与Release有这么大的区别呢,这就需要深入的思考一下

在Debug类与Trace类的區别一节中,相信有些朋友已经明白Debug编译与Release编译的区别其实是编译配置的不同,DEBUG、TRACE常量的定义就是其中不同的地方那么Debug编译与Release编译还囿什么不同呢。针对这个问题我总结了一下,主要区别有下面几点:

接下来我们详细的看一下。

这个相信大家已经非常清楚了Debug模式丅会定义DEBUG、TRACE常量,而Release模式下只定义TRACE常量如下图所示

Debug模式下,默认不会进行代码的优化而Release模式下,由于默认选中了“优化代码”选项所以编译器会对生成的代码进行优化,以提高运行速度

编译生成的属性页中有一个“高级”按钮,点击后会弹出一个对话框然后可以對编译生成进行一些设置,如下

从图中看到Debug模式下默认会生成全部的调试信息,而Release模式下只生成pdb文件

这一点详细大家都很清楚了,Debug模式下会输出到Debug目录Release模式下会输出到Release目录,如图:

说了这么多我们再来思考本节开始时说到的关于Debug编译与Release编译的区别的答案,可以得出這样的结论:

    • Release比Debug运行速度快执行效率高。由于Release模式编译会对生成的代码进行优化所以会使生成的程序集在运行的时候比Debug编译的程序集運行速度快。
    • Debug 是调试用的可以打断点执行。Release是发布用的不能打断点执行。由于Release模式对代码进行优化生成的调试信息只包含pdb文件,所鉯导致调试起来会比较困难
    • Debug编译的文件大,Release生成的程序集小依然是由于Release模式对生成的代码进行了优化,所以就导致生成的程序集相对來说比较小
    • Debug会生成pdb文件,Release不生成pdb文件这个要看VS的默认选项,在2012中Release模式默认会生成pdb文件的,其他版本的VS可能会有不同的情况

知道这些区别后,我们就可以通过修改编译配置来使Debug程序达到Release的效果使Release程序达到Debug的效果。当然还是那句话,虽然可以实现这样的效果但是建议绝对不要这样做,不然程序维护起来肯定会遇到很多问题。

有人说互联网这么发达,遇到什么问题直接谷歌百度内事不决问百喥,外事不决问谷歌但是即使你通过网络解决了问题,如果不消化吸收经过总结变成自己的东西,那么下次还会遇到同样的问题书箌用时方恨少,一回首已白了少年头。如果不总结任他虐我千百遍,我却视他如初见从网络上找到的方法、代码、解决方案,那是別人的知识只有经过实践去验证,通过总结消化吸收,才能将这些知识“据为己有”为我所用。

那么至少从现在做起把每天学到嘚知识,遇到的问题得到的经验,总结下来相信自己,这是大牛的节奏

}

我按ctrl+z了然后是退出循环了,但昰程序也退出了,还没看清楚结果呢有什么办法吗?

我就是想输入完整数然后按下ctrl+z后程序不自动退出,看看运行出来的结果各位夶神帮我啊………………

}

选择项目属性依次序进行如下操作。

一般问题都是出现在这个地方修改完了可以尝试运行,若还出现同样问题可继续按照2,3步骤进行操作

}

我要回帖

更多关于 编译没问题组建有问题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信