1、反射的定义
反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。详情可参考官网说明。
2、使用场景
需要访问程序元数据的特性;
检查和实例化程序集中的类型;
在运行时构建新类型。(使用System.Reflection.Emit中的类)
执行后绑定,访问在运行时创建的类型的方法。
3、反射的用途
(1). 使用Assembly定义或加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2). 使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或者其他特定的非全局方法。
(3). 使用ConstructorInfo了解构造函数的名称、名称、参数、访问修饰符(例如:public、private、protected等)和实现详细信息(例如:abstract或virtual等)。可使用Type类中的GetConstructors()或者GetConstructor()方法调用特定的构造函数。
(4). 使用MethodInfo了解方法的名称、返回值类型、参数、访问修饰符(同上)和实现详细信息(同上)。可使用Type类中的GetMethods()方法或GetMethod()方法调用特定的方法。
(5). 使用FieldInfo了解字段名称、访问修饰符(同上)和实现详细信息(例如:static等),也可获取或者设置字段的值。
(6). 使用EventInfo了解事件名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,可添加或移除事件处理程序。
(7). 使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或者可写状态等,可获取或者设置属性的值。
(8). 使用ParameterInfo了解参数名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
4、简单说明
大家都知道蝙蝠傍晚飞上出来找食物吃,那么它是靠什么在夜间飞行而不被撞在物体上还可以找东西吃呢?答案就是“回声定位”的原理。蝙蝠通过发出超声波可判断出物体的大小、性质和距离等。(此例可能不准确,希望大家不要吐槽哦!)
5、反射的命名空间
using System;
using System.Reflection;
6、举个简单的栗子
咱们创建一个控制台的程序利用反射技术将DataTable中的数据反射到实体上面去:
简单写一个DBHelper类,如下:
//需要引入的库
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Reflection;//提供程序反射的库
namespace NewReflectionDemo
{
public static class DBHelper
{
//数据库连接字符串
private static string connectStr = ConfigurationManager.ConnectionStrings["conStr"].ToString();
/// <summary>
/// 将DataTable中的数据反射到List<T>上面去
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dt"></param>
/// <returns></returns>
public static List<T> ToList<T>(string sql)
{
DataTable dt = null;
using (SqlConnection conn = new SqlConnection(connectStr))
{
if (conn.State != ConnectionState.Open)
conn.Open();
DataSet ds = new DataSet();
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataAdapter dap = new SqlDataAdapter(cmd);
dap.Fill(ds);
conn.Close();
dt = ds.Tables[0];
}
if (dt.Rows.Count > 0 && dt != null)
{
List<T> list = new List<T>();//定义一个集合,接收反射的数据
Type t = typeof(T);
List<string> columns = GetColumnsName(dt);//获取DataTable中所有的列名
foreach (DataRow dtRow in dt.Rows)
{
object entity = Activator.CreateInstance(t);//动态创建一个传入的对象
PropertyInfo[] pros = t.GetProperties();//获取该对象在Type中的所有公共的属性
foreach (PropertyInfo pro in pros)//遍历属性
{
string columnName = columns.Where(s => s.ToUpper().Equals(pro.Name.ToUpper())).FirstOrDefault();//获取对象在DataTable中匹配的列名
if (!string.IsNullOrEmpty(columnName))
{
object cellValue = dtRow[columnName];//根据列名获取该行该列的值
if (cellValue != null && cellValue != DBNull.Value)//判断值是否为空
{
if (!pro.PropertyType.IsGenericType)//判断该属性的类型是否为泛型类型
pro.SetValue(entity, Convert.ChangeType(cellValue, pro.PropertyType), null);//给该属性赋值
else
{
Type generic = pro.PropertyType.GetGenericTypeDefinition();//构造一个当前泛型类型的泛型类型定义的Type对象
if (generic != typeof(Nullable<>))
pro.SetValue(entity, Convert.ChangeType(cellValue, Nullable.GetUnderlyingType(generic)), null);
}
}
}
}
list.Add((T)entity);
}
return list;
}
else
return null;
}
/// <summary>
/// 获取DataTable中的列名,对应数据表列名
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
private static List<string> GetColumnsName(DataTable dt)
{
List<string> list = new List<string>();
for (int i = 0; i < dt.Columns.Count; i++)
list.Add(dt.Columns[i].ColumnName);
return list;
}
}
}
看一下调用的代码,如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NewReflectionDemo
{
class Program
{
static void Main(string[] args)
{
string sql = "SELECT * FROM Sys_EnterprisesType ";
List<Sys_EnterprisesType> list = DBHelper.ToList<Sys_EnterprisesType>(sql);
foreach (var item in list)
Console.WriteLine(item.F_TypeId + "\t" + item.F_EnterprisesTypeName + "\t" + item.F_CreateTime);
Console.ReadKey();
}
}
}
这里就简单的了解完反射咯!祝大家学习工作愉快。
保持激情;只有激情,你才有动力,才能感染自己和其他人。