反射以及Attribute在ORM中的应用

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

  1. public class Person
  2. {
  3. private string _Name;
  4. private int _Age;
  5. private string _Sex;
  6. public string Name
  7. {
  8. get { return this._Name; }
  9. set { this._Name = value; }
  10. }
  11. public int Age
  12. {
  13. get { return this._Age; }
  14. set { this._Age = value; }
  15. }
  16. public string Sex
  17. {
  18. get { return this._Sex; }
  19. set { this._Sex = value; }
  20. }
  21. }

测试代码如下:

  1. static class Program
  2. {
  3. [STAThread]
  4. static void Main()
  5. {
  6. Person person = new Person();
  7. person.Name = "snoopy";
  8. person.Age = ;
  9. person.Sex = "male";
  10. PropertyInfo[] infos = person.GetType().GetProperties();
  11. Console.WriteLine("打印属性");
  12. foreach (PropertyInfo info in infos)
  13. {
  14. //获取属性并打印
  15. Console.WriteLine(info.Name + ":" + info.GetValue(person, null));
  16. }
  17. Console.WriteLine("设置Person.Name = Hellokitty");
  18. //设置属性,设置Name属性
  19. foreach (PropertyInfo info in infos)
  20. {
  21. if (info.Name == "Name")
  22. {
  23. info.SetValue(person, "Hellokitty", null);
  24. }
  25. }
  26. Console.WriteLine("打印属性");
  27. foreach (PropertyInfo info in infos)
  28. {
  29. //获取属性并打印
  30. Console.WriteLine(info.Name + ":" + info.GetValue(person, null));
  31. }
  32. Console.Read();
  33. }
  34. }

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

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

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

  1. public class DataFieldAttribute : Attribute
  2. {
  3. private string _FieldName;
  4. private string _FieldType;
  5. public DataFieldAttribute(string fieldname, string fieldtype)
  6. {
  7. this._FieldName = fieldname;
  8. this._FieldType = fieldtype;
  9. }
  10. public string FieldName
  11. {
  12. get { return this._FieldName; }
  13. set { this._FieldName = value; }
  14. }
  15. public string FieldType
  16. {
  17. get { return this._FieldType; }
  18. set { this._FieldType = value; }
  19. }
  20. }

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

  1. public class Person
  2. {
  3. private string _Name;
  4. private int _Age;
  5. private string _Sex;
  6. [DataFieldAttribute("name", "nvarchar")]
  7. public string Name
  8. {
  9. get { return this._Name; }
  10. set { this._Name = value; }
  11. }
  12. [DataFieldAttribute("age", "int")]
  13. public int Age
  14. {
  15. get { return this._Age; }
  16. set { this._Age = value; }
  17. }
  18. [DataFieldAttribute("sex", "nvarchar")]
  19. public string Sex
  20. {
  21. get { return this._Sex; }
  22. set { this._Sex = value; }
  23. }
  24. }

通过自定义Attribute,我们定义了类属性和数据库字段的一一对应关系,我们对Person类的Name、Age、Sex属性都加上了Attribute的描述,指定了他们对应的字段名以及类型,其中Person.Name对应于字段name,字段类型Nvarchar...。

三、反射和Attribute的联合使用。
从上面的描述中,我们了解了反射,了解了Attribute,了解了ORM映射规则的定义。但是刚接触的朋友估计还是迷惑,我们怎么动态获取这些映射规则呢?听洒家慢慢道来。
这就需要使用反射了:
下面的例子,我们由于对Person中的Name,Age以及SEX都增加了DataFieldAttribute的描述,这其实就是增加了O(对象)/R(关系数据库)的映射规则,下面我们就通过反射的方法来动态获取此映射规则:

  1. static class Program
  2. {
  3. [STAThread]
  4. static void Main()
  5. {
  6. Person person = new Person();
  7. person.Name = "snoopy";
  8. person.Age = ;
  9. person.Sex = "male";
  10. PropertyInfo[] infos = person.GetType().GetProperties();
  11. object[] objDataFieldAttribute = null;
  12. foreach (PropertyInfo info in infos)
  13. {
  14. objDataFieldAttribute = info.GetCustomAttributes(typeof(DataFieldAttribute), false);
  15. if (objDataFieldAttribute != null)
  16. {
  17. Console.WriteLine(info.Name + "->数据库字段:" + ((DataFieldAttribute)objDataFieldAttribute[]).FieldName);
  18. }
  19. }
  20. }
  21. }

哈哈,你是不是很想动手了啊?当然了如果你到了这一步就开始动手的话,那我就很高兴了,说明我的描述还算清楚(注:对于已经知道的大牛们此话无效)。也说明你很有动手的能力。因为接下来的工作就是怎样根据这种方法动态地从对象中获取映射规则,动态构造Insert,Update,Delete等语句。

四、本章总结
本章中我比较详细地介绍了反射,自定义Attribute的概念和应用,并且介绍了怎样在运行时动态获取O/R Mapping的映射规则等。当然我这里的代码仅仅是举例,而要真正实现一个ORM,我们还需要考虑的很多,比如:
1、Person对应于哪张数据库表?
2、Person中的PK和FK(如果有的话)怎么表示?
......
这些问题将在我的下一篇中进行讲解。

原文链接:

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

相关连接:

C#基础系列:实现自己的ORM(ORM的基础概念)

C#基础系列:实现自己的ORM(构造我自己的ORM)

C#基础系列:实现自己的ORM(MiniORM的测试代码)

C#基础系列:开发自己的窗体设计器(PropertyGrid显示中文属性名)

源代码下载

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

  1. C#基础系列:开发自己的窗体设计器(PropertyGrid显示中文属性名)

    既然是一个窗体设计器,那就应该能够设置控件的属性,设置属性最好的当然是PropertyGrid了,我们仅仅需要使用一个PropertyGrid.SelectedObject = Control就可以搞 ...

  2. Vue基础系列(三)——Vue模板中的数据绑定语法

    写在前面的话: 文章是个人学习过程中的总结,为方便以后回头在学习. 文章中会参考官方文档和其他的一些文章,示例均为亲自编写和实践,若有写的不对的地方欢迎大家和我一起交流. VUE基础系列目录 < ...

  3. Java基础系列2:深入理解String类

    Java基础系列2:深入理解String类 String是Java中最为常用的数据类型之一,也是面试中比较常被问到的基础知识点,本篇就聊聊Java中的String.主要包括如下的五个内容: Strin ...

  4. C#基础系列-反射

    1.反射的定义 反射(Reflection),是.Net中获取运行时类型信息的方式.程序集中有关程序及其类型的数据被称为元数据(metadata).程序在运行时,可以查看其它程序集或其本身的元数据.一 ...

  5. 【Basics of Entity Framework】【EF基础系列1】

    EF自己包括看视频,看MSDN零零散散的学了一点皮毛,这次打算系统学习一下EF.我将会使用VS2012来学习这个EF基础系列. 现在看看EF的历史吧: EF版本 相关版本特性介绍 EF3.5 基于数据 ...

  6. C#基础系列——Attribute特性使用

    前言:上篇 C#基础系列——反射笔记 总结了下反射得基础用法,这章我们来看看C#的另一个基础技术——特性. 1.什么是特性:就博主的理解,特性就是在类的类名称.属性.方法等上面加一个标记,使这些类.属 ...

  7. C#基础系列——小话泛型

    前言:前面两章介绍了C#的两个常用技术:C#基础系列——反射笔记 和 C#基础系列——Attribute特性使用 .这一章来总结下C#泛型技术的使用.据博主的使用经历,觉得泛型也是为了重用而生的,并且 ...

  8. C#基础系列——委托和设计模式(二)

    前言:前篇 C#基础系列——委托实现简单设计模式 简单介绍了下委托的定义及简单用法.这篇打算从设计模式的角度去解析下委托的使用.我们知道使用委托可以实现对象行为(方法)的动态绑定,从而提高设计的灵活性 ...

  9. C#基础系列——再也不用担心面试官问我“事件”了

    前言:作为.Net攻城狮,你面试过程中是否遇到过这样的问题呢:什么是事件?事件和委托的区别?既然事件作为一种特殊的委托,那么它的优势如何体现?诸如此类...你是否也曾经被问到过?你又是否都答出来了呢? ...

随机推荐

  1. ios 计算缓存大小

    - (void)getSize2 { // 图片缓存 NSUInteger size = [SDImageCache sharedImageCache].getSize; //  NSLog(@&qu ...

  2. iOS网络-04-大文件下载

    大文件下载注意事项 若不对下载的文件进行转存,会造成内存消耗急剧升高,甚至耗尽内存资源,造成程序终止. 在文件下载过程中通常会出现中途停止的状况,若不做处理,就要重新开始下载,浪费流量. 大文件下载的 ...

  3. XCode的代码块备份

    以上三个的注释可以从下面的代码依据个数拷贝和删除: /** * <#comment#> * * @param <#one#> * * @param <#two#> ...

  4. windows下vagrant使用及工作环境配置

    环境搭建记录(2014-08-01) 操作系统: Win7旗舰版 Vagrant版本: 1.6 搭建过程 安装vagrant 右键打开安装包按照提示安装即可 安装后会自动把vagrant添加到环境变量 ...

  5. Linux 基础知识----shell

    1.file title: #!/bin/bash 2.input: echo $1 echo $2 3.if # ifif [ "$1" = "N" ]the ...

  6. Windows Server 2008 R2怎样设置自动登陆

    Windows Server 2008 R2是一款服务器操作系统,提升了虚拟化.系统管理弹性.网络存取方式,以及信息安全等领域的应用,Windows Server 2008 R2也是第一个只提供64位 ...

  7. 获取byte数组的实际使用长度

    背景:byte.length只能获取到初始化的byte数组长度,而不是实际使用的长度,因此想要获取到实际的使用长度只能靠其他方法实现. 方法一: public class ByteActualLeng ...

  8. Java小方法

    /** * 计算百分比. * @param dividend 被除数 * @param divisor 除数 * @return 结果 */ private String getPercent(lon ...

  9. 【转】App开发者必备的运营、原型、UI设计工具整理

    一.运营类 1. APPVIEW,网址:http://lab.hakim.se/appview/ 帮助iOS 应用开发者追踪所有地区App Store最近的用户评论,可以按时间.评分.地区排序,缺点是 ...

  10. xamarin.android 给View控件 添加数字提醒效果-BadgeView

    本文代码从java项目移植到.net项目   java开源项目:https://github.com/jgilfelt/android-viewbadger using System; using S ...