平台:VS2010 + SQL 2008
源码: https://files.cnblogs.com/Royal_WH/BlogTestReflection.rar
首先声明本节反射内容浅显大神就请略过吧,耽误你们的时间也不太好意思,呵呵,如果觉得我写的有用的请支持一下。
今天为大家讲一下C#里的反射,并附加一个反射数据库表实体的一个例子,我们先来看下MSDN上反射的定义:
通过 System.Reflection 命名空间中的类以及 System.Type,您可以获取有关已加载的程序集和在其中定义的类型(如类、接口和值类型)的信息。
您也可以使用反射在运行时创建类型实例,以及调用和访问这些实例。
反射提供了封装程序集、模块和类型的对象(Type 类型)。
可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。
我可以用比较简洁的话语来概括一下它:
1、可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型
2、应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
3、反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。
反射中常见的用法:
您不必创建特性的实例就可以检查它们。
以上是MSDN中反射的一些介绍和反射的一些类的用法,其实我们可以看出反射实际上就是帮我们使用,发现程序集里的一些信息。另外还有一个命名空间: System.Reflection.Emit 命名空间的类提供了一种特殊形式的反射,使您能够在运行时生成类型。 这个命名空间里执行的效率是非常高的,由于没法讲的过于深入,System.Reflection.Emit本节不做解讲,想了解他的同学们可以去看下MSDN或百度一下。 首先我们从 Module 开始讲解: 在模块上执行反射。 用法:
1private void button1_Click(object sender, EventArgs e) 2 { 3 listBox1.Items.Clear(); 4 ProjectModel model = new ProjectModel(); 5 Module m = model.GetType().Module; 6 7 Assembly curAssembly = Assembly.GetExecutingAssembly(); 8 9 listBox1.Items.Add("名称:" + m.Name); 10 listBox1.Items.Add("名称curAssemble:" + curAssembly); 11 12 Module[] mods = curAssembly.GetModules(); 13 foreach (Module md in mods) 14 { 15 listBox1.Items.Add("名称:" + md.Name); 16 } 17 18 }
当然Module还有很多的用法如Getfield(string)、GetMethod(string)都是一些常用的方法。
我们再来看下ConstructorInfo :
发现类构造函数的属性 (Attribute) 并提供对构造函数元数据的访问权。
private void button2_Click(object sender, EventArgs e) { listBox1.Items.Clear(); ProjectModel model = new ProjectModel(); Type myType = typeof(ProjectModel); Type[] types = new Type[1]; types[0] = typeof(int); // Get the public instance constructor that takes an integer parameter. ConstructorInfo constructorInfoObj = myType.GetConstructor(types); if (constructorInfoObj != null) { listBox1.Items.Add(constructorInfoObj.ToString()); } }
以上两个类为反射中的基本方法,只为大家了解一下反射。下面我来讲下如何查询数据库返回绑定的实体类:
在我的数据库DBHelper类中有以下几个方法
1#region 反射对象实体 2 /// <summary> 3 /// 通过 SQL 语句返回对象实体 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="sql"></param> 7 /// <returns></returns> 8 public static T ReaderToModel<T>(string sql) 9 { 10 try 11 { 12 using (SqlConnection con = new SqlConnection("连接字符串")) 13 { 14 con.Open(); 15 SqlCommand cmd = new SqlCommand(); 16 cmd.Connection = con; 17 cmd.CommandText = sql; 18 IDataReader dr = cmd.ExecuteReader(); 19 20 using (dr) 21 { 22 if (dr.Read()) 23 { 24 Type modelType = typeof(T); 25 T model = Activator.CreateInstance<T>(); 26 for (int i = 0; i < dr.FieldCount; i++) 27 { 28 PropertyInfo pi = modelType.GetProperty(GetPropertyName(dr.GetName(i))); 29 pi.SetValue(model, HackType(dr[i], pi.PropertyType), null); 30 } 31 return model; 32 } 33 } 34 } 35 return default(T); 36 } 37 catch (Exception ex) 38 { 39 throw ex; 40 } 41 } 42 43 44 /// <summary> 45 /// 通过SQL语句返回实体泛型 46 /// </summary> 47 /// <typeparam name="T"></typeparam> 48 /// <param name="dr"></param> 49 /// <returns></returns> 50 public static List<T> ReaderToList<T>(IDataReader dr) 51 { 52 using (dr) 53 { 54 List<T> list = new List<T>(); 55 Type modelType = typeof(T); 56 while (dr.Read()) 57 { 58 T model = Activator.CreateInstance<T>(); 59 for (int i = 0; i < dr.FieldCount; i++) 60 { 61 PropertyInfo pi = modelType.GetProperty(GetPropertyName(dr.GetName(i))); 62 pi.SetValue(model, HackType(dr[i], pi.PropertyType), null); 63 } 64 list.Add(model); 65 } 66 return list; 67 } 68 } 69 70 71 //这个类对可空类型进行判断转换,要不然会报错 72 private static object HackType(object value, Type conversionType) 73 { 83 if (IsNullOrDBNull(value)) 84 { 85 return null; 86 } 87 88 return Convert.ChangeType(value, conversionType); 89 } 90 91 private static bool IsNullOrDBNull(object obj) 92 { 93 return ((obj is DBNull) || string.IsNullOrEmpty(obj.ToString())) ? true : false; 94 } 95 96 //取得DB的列对应bean的属性名 97 private static string GetPropertyName(string column) 98 { 99 return column; 100 } 101 #endregion
大家请注意这二句,本文关键:
PropertyInfo pi = modelType.GetProperty(GetPropertyName(dr.GetName(i)));
pi.SetValue(model,HackType(dr[i], pi.PropertyType), null);
PropertyInfo类我没有讲但是我们这里提一下, 发现属性的特性并提供对属性元数据的访问。
这里我们获取他属性的名称并为他赋值然后添加到可变变量T中List<T> ReaderToList<T>则是返回实体泛型,方法类同我就不做过多讲解了!
使用反射有时是要考虑性能问题的
反射的性能: 使用反射来调用类型或者触发方法,或者访问一个字段或者属性时clr 需 要做更多的工作:校验参数,检查权限等等,
所以速度是非常慢的。所以尽量不要使用反射进行编程,对于打算编写一个动态构造类型(晚绑定)的应用程序,可以采取以下的几种方式进行代替:
1. 通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类 型的一个实例,
将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。
2. 通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。
3.通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,
然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些
好了先讲到这里一会把源码传上来,虽然没什么亮点好看不过有些同学还是上来就要源码,所以我也在以后的文章中尽量能放上源码的就放上来。
|
请发表评论