CS反射原理

C#为不同的类生成了type实例,type中记录每个类的描述数据,例如: 数据成员的名字、类型、偏移地址,函数的名字、类型、偏移地址。。。

于是我们可以通过type到的一个类拥有的所有信息。

1.C#对象的内存布局

类:是一种类型描述,描述了这个类型有哪些数据组成,同时描述一些成员函数;

类的实例: new 类() 是具体的内存对象,相当于一块内存,包含了其数据成员的集合

2.类的成员函数

类的成员函数属于代码指令,编译完成以后,会编程代码指令,全局只有一份,所有的类的实例共用一份代码指令,存入到我们的代码段。

编译器---》代码---》.exe执行文件----》运行这个文件的时候,会把里面的所有代码加载到内存的代码段;

1
2
3
4
5
6
public class person{
int name;
bool age;
public void Test1(){}
public void Test2(){}
}

类的实例中,类的数据成员的所有数据包括看得见的数据name age,也有看不见你的数据,内存对齐

  • 一个类定义好后,编译器将会记录类中成员的偏移地址(相对与类实例),这样通过类的实例也就可以得到他的成员变量

  • 同时,也会记录成员函数在代码段的偏移

3.反射如何记录类的信息

任意的类,都可以转化成这样一种描述:

类的实例是一个内存块,内存块的大小就是这个类的所有数据成员的大小。

我可以把这些数据成员的名字、类型、偏移地址通过数组等其它方式保存起来

类数据成员数组:

1
2
[{"name", type string,在对象偏移8个字节}
{ "sex" , type bool,在对象里面偏移为4个字节}]

类成员函数:

1
2
[{"test1", 成员函数(静态函数),在代码段的位置}
{"test2", 成员函数(静态函数),在代码段的位置}]

4.为什么需要反射

我们需要统一的方法来描述不同的类:

比如在制作Excel转ScriptObject或者直接将Excel的数据给到一个类,我们不可能事先知道有哪些类,也不能知道类的成员有哪些,只能通过反射根据Excel中定义的字符串来得到对应的类。

5.Type、Assembly是什么

通过上面的信息记录,编译器知道每个类的内存地址,类的各个成员的偏移地址

当运行的息时候C#会为不同的类生成这样的描述信息Type实例,相同的类共享一份这个实例,于是我们可以通过这个类的Type得到这个类的一切信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Field{
string fieldName;//字段名
int type;//类型
int fieldSize//字段大小
int offset;//内存对象中的偏移
}

public class Method{
string methodName;函数名
int type;// 静态函数 普通函数
int methodSize//字段大小
int offset;//代码段中的偏移
}

public class Type{
int size;//类实例的内存大小
List<Field> fields;//所有字段
List<Method> methods;//所有方法
}

public static class Assembly{
public static Dictionary<string,Type>() types;
}

通过Type构建类的实例

Assembly程序集中保存了所有的类,并且用类名与type做映射,通过Assembly可以通过字符串得到对应类的描述信息

type中记录了类的内存大小,于是可分配对应空间给类作为实例

type中记录了类的函数偏移地址,可以调用他的构造函数之类的。

type中记录了类的字段的偏移地址大小,可以为变量赋值。