如何高效地查看开源项目源码?

标签: 源码学习方法git


咱们为何要看源码?

这个小标题好像有点扯淡,不过我感受仍是有必要聊一聊。
最近搞 Blazor,手边常备 AspNetCore 源码,遇到问题了就翻源码。
而后有一样关注 Blazor 的同窗会一块儿讨论一些问题,我知道的问题会直接分享,我不知道的问题,我就,甩一句,“看源码”
而后有的同窗炸了,说,“不是每一个人均可以像你同样看源码,源码不是每一个人都能看的,不是每一个人都想看源码”
固然原话不是这样,后两句是我添油加醋的,不过这两句想必是大部分同窗的心声,内心惧怕看源码,以为看源码都是大神才会看的。github

看源码的正确姿式

st=>start: 遇到问题
search=>operation: 百度谷歌
isOk=>condition: 能解决吗?
donotusecode=>end: 好了你能够不用继续看了
usecode=>end: 分析源码解决
st->search->isOk
isOk(yes)->donotusecode
isOk(no)->usecode

看源码的错误姿式

st=>start: 据说看源码能学到不少东西,能经过面试,能XXXXX
usecode=>end: 看源码
st->usecode

感受第二个流程图像是在扯犊子,其实第二个图也并不是彻底错误,只是在强调你不能为了看而看,你要带着问题去看,但若是这样的话,那其实又变成了第一张流程图了面试

看源码的方法

不少同窗在知足第一个流程图的条件以后,可能看源码仍然感受累,没有头绪,这是没掌握看源码的技巧,可能存在如下几种状况网络

  • 拿着 github 在线看源码,这和拿记事本看源码没好到哪去
  • 真的就拿着记事本看源码,或者拿着 VSCode 看源码(我不是黑它)
  • 不擅于使用 VS 的相关功能

看源码必定先编译源码

不用编译直接打开 VS 一把梭,不是很好吗?
很差,确实是能够打开的,可是这个时候每每由于没有编译过致使 VS 的不少功能不可用,例如转到定义、查找引用。
对我而言,编译源码是个艰难的过程,看源码反而简单。特别是 AspNetCore 的源码,编译起来要了半条命。
关于怎么编译,每一个开源项目都不同,有的项目简单,打开 VS 直接就能编译,可是像 AspNetCore 这种,必须严格按照官方给的编译步骤文档,还得保证网络畅通,编译过程当中很容易被劝退。单元测试

五大板斧不可少

有不少同窗看源码的过程让我比较着急,咋看的呢?
CTRL+F,输入搜索词,全解决方案搜索,不论是怎样的状况全是这样搞,解决方案比较大的话一搜一大堆出来。
也许只是我周围的同窗是这样的吧。
我看源码的过程当中常使用这些方法学习

  • 转到定义,F12
  • 转到实现,CTRL + F12
  • 查找引用
  • 调用堆栈
  • 解决方案管理器搜索

这五大板斧中,除了调用堆栈,其余的几乎都是静态分析代码的必备方法,调用堆栈通常属于动态分析代码的办法。
这五大板斧用好了,只要源码的变量命名不要太坑爹,基本上是不须要看注释的,我看开源项目的源码历来不看注释,开源项目的源码的命名通常都是比较好的。测试

下面我将举例来分享我看源码的过程,把上面这几个方法用上code

问题实例:怎么根据路由获取对应的组件?

这是我在编写 BlazAdmin 时遇到的问题,我须要根据当前路由获得这个路由对应的那个组件,而后作一些操做,我甚至不知道如何搜索,由于关键词很差搞,随便搜了几个也没找到答案。component

下面开始分享我针对这个问题的解决思路,下载编译 AspNetCore 源码的步骤我就不写了blog

第一个问题,从哪儿开始?

万事开头难,刚开始看源码更难,无头苍蝇的感受。
咱们的需求是,怎么根据路由获取对应的组件,这里面有两个关键词,一个是路由,一个是组件
咱们换位思考一下,假如由咱们来开发这个功能,咱们会写哪两个类?
答案应当很明显,RouterComponent,固然也许不是这么命名的,都有可能。但好像知道这两个名字了仍是没啥用?根本问题在于 AspNetCore 解决方案太多,咱们压根不知道应该打开哪一个解决方案,也就无从搜索这两个类名。
个人办法是,也许这两个类咱们是能够直接使用的,那么若是能够直接用的话,咱们应该能够在代码的任意地方调用这两个类,那么咱们就试试。
在咱们本身项目的 Program.cs 文件中,随便找个地方,咱们首先尝试 Router 关键字。
image.png-36.5kB

好像有戏,咱们已经看到命名空间了,那么根据这个命名空间,咱们尝试找到对应的解决方案,这个命名空间的关键词是什么呢?Microsoft?AspNetCore?这两个关键词太大众化了,那么只剩下两个,Components 和 Routing,咱们一个一个来

image.png-78.9kB
image.png-61.3kB

没啥好说的,既然找到了,管它是否是,先打开看看再说。

image.png-31.1kB

咱们直接在解决方案管理器中搜索这 Router 这个类。

image.png-41.9kB

咱们的入口点已经显而易见了

image.png-27.6kB

第二个问题,这个类是如何找到 Component 的?

这个类中有这么些方法

image.png-23.7kB

根据方法猜功能,没错,看源码全靠猜,猜错了换条路继续

OnAfterRenderAsync 这个应该不是
OnLocationChanged 这里面都有些啥?

image.png-8.9kB

这里面调用了 Refresh 方法,F12 跟进去

image.png-31.1kB

开始发晕了,咋这么多呢,并且还不明显,咱们一行行看,一行行猜
看第五第六行,这两行有点意思,跟当前路由有关,也许是咱们想要的
F12 进 RouteContext,看看里面有啥

image.png-26kB

好吧啥也没有,咱们继续看第六行,F12 进 Route 方法

image.png-16.1kB

愈来愈像了,Match 方法里面又是什么呢?F12 进去

image.png-33.6kB

这个方法中看起来也不像那么回事,不过仍是有点有用信息,最后一句代码将 Handler 赋值了一下,但问题是 Handler 是啥?看这命名有点像当前路由的处理器,那么这个处理器可能就是咱们要找的 Component,从构造方法中能够看出这个 Handler 是由构造方法传过来的,构造方法能够看到还有一个引用,意味着有地方在显示调用,那么咱们经过查找引用跳过去看看

image.png-31.4kB

看来这就是咱们要找的了,愈来愈近了,这里应该是在分析路由模板,那么路由模板应该是调用这个方法的地方传过来的,再次查找引用跳过去

image.png-17.5kB

两个地方在调,咋办?明显能够看出第一个地方是单元测试调的,因此其实只有第二个地方在调

image.png-20.4kB

Template 就是路由的模板,而这个模板是由 RouteAttribute 特性来获得的,而这个特性是标记在每个组件的 Type 上的,也就是说,只要获取全部组件的 Type,就能够拿到全部组件对应的路由,这样一来,个人问题解决了

总结

  • 大胆猜想,当心求证
  • 换位思考,若是是我,我会怎么命名,这个经常使用于寻找分析入口点
  • 英语别太差,不过通常来讲你坚持看源码英语会提高的
  • 不要 CTRL + F,不要 CTRL + F,不要 CTRL + F,多用 F12,查找引用
  • 在某些特殊状况下,例如别人都是经过反射调用的,那么就只能 CTRL + F 了

能够看到,解决这个问题的过程几乎全是靠猜,猜错了就回过头去猜下一个,猜对了那就对了。因此若是说某个开源项目的命名太糟糕,那就确实很差找了。当你看源码看多了以后,你就不须要猜了,由于你已经知道命名是啥了。

在这个示例中,咱们没有使用转到实现,由于其实这个示例所涉及到的代码仍是简单的,没有涉及到太多的多态,所以不须要转到实现。若是涉及到多态,那么过程会复杂不少,由于要看的路径太多,但总归是能看完的,相比用谷歌去搜索半天压根就没有头绪,花点时间猜源码仍是值的。

相关文章
相关标签/搜索