承接着上一篇, 这一篇主要以堆栈的方式来演示一下, db数据转换到类中去的一个过程.
一、先看第一张图
程序在运行到176行(上一篇贴出的代码)的时候, 就会出现上图中的第一个栈.
那在此之前, Dapper又做了些什么呢? 抛开Dapper的这种OpCodes的实现方式来说, 我们自己用代码去转换, 实现思路如下:
1. 首先肯定是要获取, 从db读取出来的那么多列中, 有哪一些是需要转换的吧, 如果是select * , 那会读取出所有的列, 但是我本身并不需要那么多列, 而且, 我接收的类, 本身可能并没有那么多的列, 所以, 首先确定有哪些列需要转换, 以及这些列从db中读取出来是什么类型的.
2. 当确定好有效的列之后, 就可以获取类中的构造函数, 已备创建类的时候使用. 在获取构造函数的时候, 当然是越简单的构造函数越好.(Dapper中会优先检测标有ExplicitConstructor属性的构造函数, 然后获取构造函数的参数, 然后初始化参数), 然后就是把这个类new出来.
3. 到现在, 我们其实就已经能知道source data type 和 target property/feild type了, 既然已经两边的类型都已经知道, db数据已经准备好, target class也已经new好了, 就可以来实现转换了, 根据类型的不同, 来使用不同的转换. 值得一提的事, 如果 target class中, 含有自定义类的属性或者字段, Dapper是不会继续转换的, 直接给了个null就了事了. 其实Dapper中, 也是可以实现此功能的, 这部分以后再说.
那么现在回到Dapper里来, 其实他做的工作也是这样子的, 顺序可能稍有不同, 1,2的顺序是可调的. 只是他实现的方式稍有不同而已. 条条大路通罗马, 目的地都是相同的, 不同的是途中的风景.
二、接着第二张图
上图中的第一个栈, 是执行完 181行 代码之后, 出现的情况, 180行, 181代码的意思, 其实就是把 reader[index]复制一份到 loc2中, 这个loc2就是前面(161行)声明的, 类型为object的本地变量, 所以, 从堆栈的情况来看, 180行未执行前, 和181行执行完之后的堆栈是一样的. 所以我就不画了.
在执行Unbox_Any之前, 是已经知道source type和target type了, 并且已经经过判断, 是否能够转换, 然后再通过Unbox_Any来转, Unbox是拆箱操作, Unbox_Any是拆箱成你需要的类型
上面这两幅图就是正常情况下(int, string, datetime, double等)的堆栈变化过程了, 应该还是比较能辅助理解的了.