Just Reflect

前阵子同事问了我些Hashtable原理的问题,关于对象怎样匹配等。我回答说:@#$%^&. 他继续问,哪里有这方面的资料.我说,没有,我猜的。然而他对我笑了笑表示怀疑。我笑着说,不信我可以试给你看。于是我拿出神器:Reflector.

用Reflector我们可以看到Hashtable的Contains方法调用了ContainsKey.

image

image

ContainsKey方法里前13行do之前对key求了次hash,然后根据生成的index在buckets里找,如果那个位置没有找到就认为没有这个key存在,直接返回空。如果有值,并不是简单地把这个值返回,而是再对要对象进一步做判等操作

详细看下KeyEquals方法就能得到结果。为了效率问题首先用ReferenceEquals判等,然后用Hashtable默认的Comparer判断,最后调用对象的Equals。所以说两个对象相不相等是由Equals说了算,跟hash code没关。好的hash code只是减少碰撞机会,提高性能。

反过来,我想大家也应该知道了为什么重写Equals方法后,需要重写对应的GetHashCode方法,因为是先拿hash code去检测的。不同对象产生了同样的的hash code只会影响性能,不会影响结果,然相同的对象如产生的hash code不一样则会影响到正常的结果,后果只能自付:)

 

自从工作以来发现自己用Reflector的时间越来越多了。记得做第二个项目的时候,有个任务是研究Arx怎么使用。当时完全不知道这个是干啥的,美国头头对这个也不是很熟悉,自己事情又多就丢给我们这边研究了。接到任务首先Google之,哦发现是做Autocad二次开发用的,有托管的对cad的API进行了封装过。而且还只需2个dll,于是我就拿Reflector加载了dll,看看里面是怎么调用的,一边猜一边试,半天不到还真让我摸到头绪了,汇报给美国,那边回信表示很吃惊,听口气好像猜我以前做过这方法的事。

尝过一次甜头后,以后就经常有事没事reflect一下,自己个性又比较喜欢寻根究底的,而Reflector正好可以告诉我很多这方面的。有时候我很喜欢猜,猜测FCL的collection是怎么实现的,就拿Reflector查看一下就好,如何猜的不对就会深挖下,里面实现的机制到底是怎么的。

去年项目上要研究类似于form designer的玩意,Dev express刚好提供了这样的一套控件,然后我就负责研究其能不能应用到我们的项目中来,功能够不够强大。当然这个控件对我来说还是很陌生的,拿到之后我还是很习惯地reflect了一下,依然去猜测它提供怎样的功能,类于类之间是怎么组织的(实际上第一步是拿到Demo程序瞎整,好多东西从行为上是能猜到的,然后再拿reflector验证研究)。虽然官网上有帮助文档,但我还是不会很习惯地去看那些东东。一个英语不好理解起来有时候挺费劲的,一个觉得从其中能获得的信息是有限的,人家只是简单地向你介绍API,细节的东西,原理性的东西是不会透露的。我总是整整后再去胡乱地翻一遍帮助文档,补补遗。

对于Overview,架构图,Design文档还是要先看的,但第一次我总仅限于囫囵吞枣。个人还是倾向于尽快地切入到代码中,觉得代码才是最真实的,包含的信息也是最丰富的。对于如何看代码,人人都有自家的一套。我倾向于先猜,再验证。粗略看了设计文档,对于各个模块的层次结构功能应该有大致的了解了。看文档有个风险就是你是否真的理解了,你觉得自己理解了,功能是这样这样的,这其实也是个“猜”,至于是否真的像你理解的那样这还是个未知数。然后就点点各个模块看看类名,类的大致结构,私有成员一般都要猫上几眼。 觉得有点概念了就先跳过。 然后就是稍作休息,思考思考看看大体上能不能勾勒出来。对于了解某块功能的过程也大体如是。看到一个方法就根据其签名猜功能,有注释的再看几眼,如果两者没有太多冲突就点进去看是看一下。 对于一些不明白的地方就跟的细一点深入一点,多花点时间去消化。基本上代码跟进的力度是根据自己主观判断对其的把握程度来决定。

而且我比较喜欢重构里提倡的小函数和自解释的方法。比方说一个方法要完成其功能要分5步走,实现每一步均要6行代码。很多人就喜欢将这30行代码都写在一个函数里,负责点的在每步前给个注释,12345干吗干吗的。而我就喜欢将每一步都抽取成一个小函数,给每个小函数取个能表达自身功能的名字(注释就可有可无了),主函数里就只有5行代码。这样做到主要到不是为了将来能重用这些小函数,主要是这样的布局适合我”猜“的方式。看5行代码就能理解的事情,为啥要眼睛注视到30行代码上。看不懂其中的某个步骤可以再点进去看个究竟嘛。

”猜“的方式很大程度上还是依赖于经验,经验老道的人猜错的几率比较小些,可能不需要深入到代码太深的细节,太太地节约了时间。而且深入太深覆盖太广的话也容易迷失自我,把握不了全局。偶尔的时间不如稍作休息,思考思考,尽量做到能把刚才看过的那些东西链接起来。

 

(PS.很久以前写的,当时没写完,现在重拿出来却不知道接下来要写什么了:))

最近在看《.Net 2.0应用程序调试》一书,里面提到一点就是,要带有目的的去调试。那目的是什么,怎么来的?其实就是先分析已知的,猜测问题可能出在哪,然后集中精力去攻破这一点,而非漫无目的的瞎整。当然很多时候我们前几次会猜错,当随着我们攻破了一个又一个关键点后,我们的知识架构体系就会越来越具体越来越接近事实,下次猜出来的东西就能逼近事实。我想这个过程跟我上面提到的学习过程有着异曲同工的效果。

posted @ 2008-12-15 17:40  Anders06  阅读(2074)  评论(8编辑  收藏  举报