C# - 反射学习,附带绑定实体类从数据库查询数据中,带源码学习!

平台:VS2010 + SQL 2008

源码: http://files.cnblogs.com/Royal_WH/BlogTestReflection.rar

首先声明本节反射内容浅显大神就请略过吧,耽误你们的时间也不太好意思,呵呵,如果觉得我写的有用的请支持一下。

今天为大家讲一下C#里的反射,并附加一个反射数据库表实体的一个例子,我们先来看下MSDN上反射的定义:

通过 System.Reflection 命名空间中的类以及 System.Type,您可以获取有关已加载的程序集和在其中定义的类型(如接口值类型)的信息。 

您也可以使用反射在运行时创建类型实例,以及调用和访问这些实例。

反射提供了封装程序集、模块和类型的对象(Type 类型)。

可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。

我可以用比较简洁的话语来概括一下它:

1、可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型
2、应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
3、反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。
反射中常见的用法:
  • 使用 Assembly 定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。
  • 使用 Module 发现以下信息:包含模块的程序集以及模块中的类等。 您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
  • 使用 ConstructorInfo 发现以下信息:构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。
  • 使用 Type 的GetConstructors 或 GetConstructor 方法来调用特定的构造函数。
  • 使用 MethodInfo 发现以下信息:方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。 
  • 使用 Type的 GetMethods 或 GetMethod 方法来调用特定的方法。
  • 使用 FieldInfo 发现以下信息:字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值。
  • 使用 EventInfo 发现以下信息:事件的名称、事件处理程序数据类型、自定义特性、声明类型和反射类型等;并添加或移除事件处理程序。
  • 使用 PropertyInfo 发现以下信息:属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。
  • 使用 ParameterInfo 发现以下信息:参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。
  • 当您在一个应用程序域的仅反射上下文中工作时,请使用 CustomAttributeData 来发现有关自定义特性的信息。 通过使用 CustomAttributeData
您不必创建特性的实例就可以检查它们。

以上是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.通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,

然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些 

好了先讲到这里一会把源码传上来,虽然没什么亮点好看不过有些同学还是上来就要源码,所以我也在以后的文章中尽量能放上源码的就放上来。

转载于:https://www.cnblogs.com/Royal_WH/archive/2011/03/14/1983790.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
private void btnCreateEntity_Click(object sender, EventArgs e) { HeaderOfEntity HeaderOfEntity = new HeaderOfEntity(); DataTable dt = new DataTable(); #region 实例化一个实体,并为这个实体类赋值 //实体类名不能为空 if (txtClassName.Text == "") { MessageBox.Show("类名不能为空!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } else { HeaderOfEntity.ClassName = txtClassName.Text.Trim(); } //实体类的说明 if (txtClassExplain.Text != "") { HeaderOfEntity.ClassExplain = txtClassExplain.Text.Trim(); } else { HeaderOfEntity.ClassExplain = ""; } //实体类的作者 if (txtAuthor.Text != "") { HeaderOfEntity.ClassAuthor = txtAuthor.Text.Trim(); } else { HeaderOfEntity.ClassAuthor = ""; } //类的命名空间 if (txtNamespace.Text != "") { HeaderOfEntity.NameSpace = txtNamespace.Text.Trim(); } else { HeaderOfEntity.NameSpace = ""; } #endregion #region 将dataGridView数据复制出来,复制到DataTable,做为参数 //添加列 for (int i = 0; i < dgvAttribute.Columns.Count; i++) { dt.Columns.Add(dgvAttribute.Columns[i].Name); } //添加行 for (int j = 0; j < dgvAttribute.Rows.Count; j++) { DataRow dr = dt.NewRow(); for (int k = 0; k < dgvAttribute.Columns.Count; k++) { dr[k] = dgvAttribute.Rows[j].Cells[k].Value; } dt.Rows.Add(dr); } #endregion string strFileName = "\\" + txtClassName.Text + ".cs"; //实例化一个接口对象 IWriteEntity writeEntity = new WriteEntity(); string strPath = "../../CreateClass"; FileStream fs; if (!File.Exists(strPath + strFileName)) { fs = new FileStream(strPath + strFileName, FileMode.Create,FileAccess.Write); } else { fs = new FileStream(strPath + strFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); } if (writeEntity.Write(fs, dt, HeaderOfEntity) == true) { MessageBox.Show("写入文件成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show("写入文件失败!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error); } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值