于是我进行更深入的比较,比较除了源文件之外,它的项目设置和我的项目设置有什么区别——还是没有!我抱着最后一丝希望,将A项目中的代码添加到我的项目中来,编译,还是失败!但是看到这个结果,我反而看到了解决问题的曙光。因为我都已经把源代码统一了,这样可能发生错误的地方可谓少之又少。刚才我提到,VS将编译工作交给外部命令执行,对于F#也一样。于是我就比较项目A和我的项目在编译时的输出,终于发现两者的区别在于调用fsc.exe的时候,参数顺序不同。F#的编译器和C#编译器不同的地方在于,它对源文件指定的顺序是有要求的,只有放在后面文件中的代码才能访问到前面文件中定义的内容,反之则不行。这意味着,main方法必须作为最后一个源文件存在。但是,VS并没有提供一个选项来调整源文件的顺序,既然这样,那就手动编辑fsproj文件吧。至此,问题解决。
我被这个问题困扰很久的原因,就是在于我从来没有去怀疑过F#编译器对源文件的指定顺序是有要求的。我之前也观察过fsc.exe的参数,但是并没有“看出”什么问题出来。但是,我会和一个成功的项目慢慢比较,把我的项目和它慢慢靠拢,我用这种方式排除了各种错误可能性,最终把我的关注点又“逼迫”到编译器的参数上。进行比较,尝试,最终解决问题。再此之前,我也不知道这一点,不是吗?您其实也一样,如果遇到了一个奇怪的问题,没关系,找一个成功的案例,详细比较为什么它能行而我不行,慢慢地向它靠拢。最终解决问题的时候,就是你获得新知识的时候。这样,你的“经验”增加了。
类似的做法还有:不时有朋友会问到,它的 WebForm项目出现了这样那样的问题,例如在PostBack之后事件没有执行,状态没有恢复,读不到某个值等等。从我的经验上来说,这是遇到了生命周期的问题。但是,生命周期是个复杂的玩意儿,除非我亲手进行尝试,我也不可能知道某个特定项目特定问题的解决方案。其实对于这种问题,最好的方法之一,便是从最简化的模型开始尝试。例如,您可以准备一个空白页面,添加一些控件和代码,执行,成功。然后,您将这个简单的页面向您的项目进行靠拢,一次增加一小部分,然后执行看看是否成功。直到某段代码添加之后发现失败了,您就知道到底是什么原因引起的。可能是新的代码有问题,也可能是新代码让之前代码的问题暴露出来了。
对于排错来说,最关键的是思考和分析,而不是动手。我有时候见到一些同事在遇到错误之后就开始盲目地修改代码,重试,最后就算把问题碰对了,时间也浪费了——而且还可能把原有正确的地方改坏了。要进行思考和分析,就要细心观察,例如您有没有看清异常的信息是什么?有没有顺着InnerException一级一级往下看,看看最终是哪行代码出的问题?如今的框架,一般都会把错误信息写的非常完整。记得之前做WCF的时候,它甚至会告诉你可以尝试着修改配置中的哪个节点!如果您直接忽视这些,就丧失了第一手信息了。
还有,别怕英文,就个错误信息而已,没几个词的。
但是我可以这么说,许多朋友都缺少思考。因为从他们给我的邮件上来看,根本没有把问题描述清楚。我相信“如果说不清楚,那说明没想清楚”。事实上,如果能把问题描述清楚了,一般也可以找出用什么关键字去搜索引擎上查找信息。我很奇怪,许多朋友还不会用搜索引擎,例如他们会对搜索引擎说很长一句话,而不是提取出中间的“关键字”进行查询。更严重的问题是“造词”。例如“注入”,这个词很流行啊,脚本注入,SQL注入。于是很多人在提问