C#之反射学习入门简介
在c#中,通过反射能够更加灵活高效地实现想要的功能,接下来我们就一起来看看反射到底能给我们带来什么好处
首先新建一个接口类库
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DB.Interface
{
public interface IDBHelper //定义一个接口
{
void Query(); //定义一个方法
}
}
然后生成dll文件
接着新建一个DB.Sqlserver类库,并实现上面的接口(在该类库中要引用上面类库生成的dll文件)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DB.Interface;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Text;
namespace DB.Sqlserver
{
public class DBHelper : IDBHelper
{
private string connString = ConfigurationManager.AppSettings["YHConnect"];
private SqlConnection conn;
public DBHelper()
{
Console.WriteLine("连接SqlServer");
conn = new SqlConnection(connString);
}
public void Query()
{
Console.WriteLine("这里是{0}的Query", this.GetType().FullName);
Console.WriteLine("此为无参方法");
}
public void Query(string id)
{
Console.WriteLine("参数为{0}", id);
}
private void test()
{
Console.WriteLine("私有方法");
}
}
然后采用同样的方法生成该类库的dll文件,然后再添加一个控制台程序
并为该引用程序添加对接口DB.Interface的dll文件的引用。此时项目的文件结构如图所示。
接下来的关键步骤就是要把DB.Sqlserver的dll文件复制到控制台程序的bin目录下
也就是要把DB.Sqlserver.dll文件从第一幅图的路径复制到第二幅图的路径下。主要是为了在控制台程序中能动态加载到这个dll文件。
然后为控制台程序添加一个配置文件
接下来在控制台程序中添加一下代码来动态加载dll文件
然后再配置文件中的configuration节点添加以下代码
<appSettings >
<add key="SqlHelper" value="DB.Sqlserver.DBHelper,DB.Sqlserver"/>
</appSettings>
用来配置dll的信息,其中DB.Sqlserver是dll文件的文件名,DB.Sqlserver.DBHelper指向了该dll中具体的某个类,即DB.Sqlserver命名空间下等的DBHelper类。
1 动态加载dl并实例化对象
至此准备工作已经做完,接下来就可以在控制台程序中动态地调用dll文件了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Configuration;
using Model;
using DB.Sqlserver;
namespace MyReflection
{
public class Program
{
static void Main(string[] args)
{
string spaceName = ConfigurationManager.AppSettings["SqlHelper"]; //可配置
string[] nameArray = spaceName.Split(','); //从配置文件获取dll文件信息
Assembly ammenblyDBHelper = Assembly.Load(nameArray[1]); //反射的入口 动态加载一个dll文件
Type dBHelperType = ammenblyDBHelper.GetType(nameArray[0]);//获取盖扩展程序中的某个类
Object dBHelperObject = Activator.CreateInstance(dBHelperType); //实例化对象
}
}
}
2 访问实例化出来的对象的方法和属性
此时我们就已经获取到了dll文件,并实例化了DBHelper类的对象,但此时这个对象时Object类型的,无法访问DBHe类的具体属性和方法。接下来我们来继续学习如何获取该对象下的方法。
我们课采用Type.GetMethod()来获取指定的某个方法 可参考MSDN文档
//动态加载方法并调用 加载无参方法
// 第一个参数表示方法名称,第二个表示该方法的参数类型
MethodInfo QueryDoMain = dBHelperType.GetMethod("QueryDoMain", new Type[] { });
//调用刚才获取到的方法,并给出参数数组,第一个参数为该方法所属的对象
QueryDoMain.Invoke(dBHelperObject, new Object[] { "123" })
也可采用Type.GetMethods()方法来获取某个对象下的所有方法,该方法返回的是一个MethodInfo[]方法,可用foreach()来遍历。
上述方法只能获取访问属性为public的方法,若要获取访问属性为private的 test()方法,可用以下方法是来获取
//获取私有方法
MethodInfo Test = dBHelperType.GetMethod("test", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Test.Invoke(dBHelperObject, null);
同样我们可以采用Type.GetProperties()`方法来获取某个Type类型变量下的所有属性,返回的是一个PropertyInfo[]数组,同样可用foreach()来遍历。
PropertyInfo id = typePeople.GetProperty(“id”); // 获取某个Type下的属性
PropertyInfo name = typePeople.GetProperty(“name”);
id.SetValue(oPeople, “123”, null); //设置值
name.SetValue(oPeople, “LC”, null);
3 反射的可配置
反射之所以可配置,就是因为它是通过dll的文件名来动态加载dll文件的(前提是该dll文件要放在指定目录下)。可通过修改配置文件中的相关信息来加载不同的dll文件
再添加一个与DB.Sqlserver类似DB.Mysql类库,同样要添加对DB.Interface.dll的引用,再生成该类库的dll文件,然后将该dll文件复制到控制台程序的Debug文件夹下。
此时若想ammenblyDBHelper加载的是DB.Mysql的dll,只需将App.congfig的
<add key="SqlHelper" value="DB.Sqlserver.DBHelper,DB.Sqlserver"/>
/>
改成
<add key="SqlHelper" value="DB.Mysql.DBHelper,DB.Mysql" />
因为配置文件修改了,所以就会加载不同的dll(应用程序扩展)文件。
4 通过反射和泛型实现数据库表的通用查询功能
首先是数据库的连接配置,在App.congfig添加数据库的连接信息
<add key="YHConnect" value="Data Source=.;Initial Catalog=YH;Integrated Security=True"/>
接下来创建实体层,即Model类库,并添加Employee类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Model
{
//员工实体
public class Employee
{
//员工表的属性
public string JobNumber { set; get; }
public string Name { set; get; }
public string Pwd { set; get; }
public int EmployeeState { set; get; }
}
}
然后为该类库生成dll文件,并为控制台程序引用该类库。
接下来在DB.Sqlserver命名空间下的DBHelper类添加查询方法
public List<T> QueryDoMain<T>()
{
conn.Open();
Type type = typeof(T); //定义T类型的Type对象
string[] propertiesArray = new string[] { }; //表中的字段数组
List<string> strList = new List<string>(propertiesArray);
foreach (var proper in type.GetProperties()) //遍历获取该Type下的所有属性
{
strList.Add(proper.Name);
}
propertiesArray = strList.ToArray();
string columns = String.Join(",", propertiesArray);//对字段数组中个元素用逗号拼接成字符串
string sql = string.Format("select {0} from {1} ", columns, type.Name);
SqlDataAdapter adapter = new SqlDataAdapter(sql, conn);
DataTable dt = new DataTable();
adapter.Fill(dt);
T t = default(T); //创建T类的对象 并赋值T类型变量的默认值
List<T> tList = new List<T>(); //创建T类型的List
for (int i = 0; i < dt.Rows.Count; i++) //遍历查询结果
{
t = (T)Activator.CreateInstance(type);
foreach (var proper in type.GetProperties())
{
proper.SetValue(t, dt.Rows[i][proper.Name], null);
}
tList.Add(t); //实例化多个T类的对象 并添加到List中
t = default(T);
}
return tList;
}
然后再控制台调用DBHelper类中的该方法
DBHelper dbHelper = new DBHelper();
List<Employee> employeeList = dbHelper.QueryDoMain<Employee>();//调用泛型方法