C#基础系列:实现自己的ORM(反射以及Attribute在ORM中的应用)

时间:2021-10-04 02:16:07

反射以及Attribute在ORM中的应用

一、 反射
什么是反射?
简单点吧,反射就是在运行时动态获取对象信息的方法,比如运行时知道对象有哪些属性,方法,委托等等等等。
反射有什么用呢?
反射不但让你在运行是获取对象的信息,还提供运行时动态调用对象方法以及动态设置、获取属性等的能力。
反射在ORM中有什么用呢?
我这里所讨论的ORM实现是通过自定义Attribute的方式进行映射规则的描述的。但是我们并不知道具体哪个对象需要对应哪个表,并且这些对象是独立于我们的ORM框架的,所以我们只能通过自定义Attribute来定义映射规则,然后通过反射来动态获取这些映射规则。
反射的实现:
下面我们就以简单的获取对象的属性值的方式来做讨论,假设我们有类Person,其中有3个属性Name、Age,Sex。我们通过反射的方法来动态获取Person的对象的这三个属性的值。

public class Person { private string _Name; private int _Age; private string _Sex; public string Name { get { return this._Name; } set { this._Name = value; } } public int Age { get { return this._Age; } set { this._Age = value; } } public string Sex { get { return this._Sex; } set { this._Sex = value; } } }

测试代码如下:

static class Program { [STAThread] static void Main() { Person person = new Person(); person.Name = "snoopy"; person.Age = 5; person.Sex = "male"; PropertyInfo[] infos = person.GetType().GetProperties(); Console.WriteLine("打印属性"); foreach (PropertyInfo info in infos) { //获取属性并打印 Console.WriteLine(info.Name + ":" + info.GetValue(person, null)); } Console.WriteLine("设置Person.Name = Hellokitty"); //设置属性,设置Name属性 foreach (PropertyInfo info in infos) { if (info.Name == "Name") { info.SetValue(person, "Hellokitty", null); } } Console.WriteLine("打印属性"); foreach (PropertyInfo info in infos) { //获取属性并打印 Console.WriteLine(info.Name + ":" + info.GetValue(person, null)); } Console.Read(); } }

上面演示了通过反射的方法来动态获取和设置对象属性的方法。但是这和ORM以及Attribute有什么关系呢?这个是我们接下来的这个部分的内容。


二、Attribute的使用:
Attribute中文翻译虽然也号称“属性”,但是她和对象的属性(Property)其实是完全不同的两概念。她是在运行时对对象或者对象属性、方法、委托等等进行描述的类,用于在运行时描述你的代码或者在运行时影响你的程序的行为。
其实我们在c#的编程中经常看到Attribute,只不过我们没有注意罢了。比如Main函数前的“[STAThread]”这个其实就是一个Attribute。全程为[STAThreadAttribute]。另外指定类可序列化的[Serializable]等等。是不是都很熟悉啊?只不过平时估计没有用到,所以没有注意罢了。

既然Attribute是类,那么她的定义方法和类就没有两样了,唯一的不同就是自定义Attribute类必须继承于System.Attribute。
下面我们来简单定义一个描述数据库字段信息的Attribute,在此类中我们采用更省略的方式,仅仅提供“字段名”,“字段类型”:

public class DataFieldAttribute : Attribute { private string _FieldName; private string _FieldType; public DataFieldAttribute(string fieldname, string fieldtype) { this._FieldName = fieldname; this._FieldType = fieldtype; } public string FieldName { get { return this._FieldName; } set { this._FieldName = value; } } public string FieldType { get { return this._FieldType; } set { this._FieldType = value; } } }

好,我们有了自己的描述数据库字段的Attribute,那么我们现在将其应用到实际的类中。我们还是继续上面的Person类,使用方法如下: