平台:VS2010 + SQL 2008
源码: http://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 开始讲解:
在模块上执行反射。
用法:
1 private 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.通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,
然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些
好了先讲到这里一会把源码传上来,虽然没什么亮点好看不过有些同学还是上来就要源码,所以我也在以后的文章中尽量能放上源码的就放上来。