什么是反射与反射的应用及调用方法
前言
1.ILspy:逆向工程:可以把Dll/Exe文件反编译回来;
2.IL:是对标于C#代码的代码,不太好阅读
3.metadata:是一个清单数据,只是记录有什么,而不是展示所有的实现;明细账本
4.反射是System.Reflection命名空间,可以读取metadata,并使用metadata;是微软提供的一个帮助类库;
5.下图举例使用ILSpy打开我写的一个实体类。如果使用IL方式呢,我们看到的程序不是很明朗。
6.如果使用C#查看,就可以得到我原本写的代码了。
为什么学习反射
答:因为反射真的是无处不在,ORM/MVC/IOC;
- 在MVC编程中比如 “Home/Index” 这样的路径来访问程序文件中的特定类。其实用到的就是反射。
- 可以利用反射来生成实体类对象。
- 可以利用反射来根据实体类生成自动的查询语句与返回对象。
- 反射可以实现程序的解耦(不需要添加项目引用即可使用类)。
- 反射可以实现动态配置来实现程序的高可用。
1.反射创建对象
1.目前的结构如上图。调用的方法如下图与代码。
2.加载dll动态库有很多种方式,推荐使用这种方式Assembly.LoadFrom原因:
- 不需要添加对dll的引用,只需要把dll拷贝到发布目录下即可使用。
- 不需要全路径,只需要写上DLl的名称即可。PS:后缀要加上 .dll
public static IDBHelper getClass()
{
//获取数据清单metadata
Assembly assembly3 = Assembly.LoadFrom(@"HomeWork.SqlHelper.dll"); //dll名称(需要后缀)
///2.获取类型
Type type = assembly3.GetType("HomeWork.SqlHelper.SqlServerHelper");
//创建实例
object obj = Activator.CreateInstance(type);
//类型转换。
return obj as IDBHelper;
}
2.反射调用方法
通过在上边的简单工厂后,我们实例出来一个接口对象IDBHelper。
接下来就可以通过接口点方法进行使用。
Console.WriteLine("获取反射类开始!");
IDBHelper iDBHelper = SimpleFactory.getClass();
5.调用方法
Company company = iDBHelper.Find(1);
Console.WriteLine("获取反射类完成!");
3.反射调用带参数构造方法
{
Console.WriteLine("*********************Reflection创建带构造函数参数的对象*************************");
Assembly assembly3 = Assembly.LoadFrom("HomeWork.SqlHelper.dll"); //dll名称(需要后缀)
Type type = assembly3.GetType("HomeWork.SqlHelper.SqlServerHelper");
object obj = Activator.CreateInstance(type);
object obj1 = Activator.CreateInstance(type, new object[] {
"你好" });
object obj2 = Activator.CreateInstance(type, new object[] {
123 });
object obj3 = Activator.CreateInstance(type, new object[] {
123, "你好" });
Type type1 = typeof(SqlServerHelper);
}
4.反射调用方法
{
//Type type1 = typeof(ReflectionTest);
//普通调用方式
ReflectionTest reflectionTest = new ReflectionTest();
reflectionTest.Show1();
reflectionTest.Show2(123);
reflectionTest.Show3(123);
//reflectionTest.Show4
ReflectionTest.Show5("Richard");
//Console.WriteLine("*********************Reflection调用普通方法*************************");
Assembly assembly3 = Assembly.LoadFrom("HomeWork.SqlHelper.dll"); //dll名称(需要后缀)
Type type = assembly3.GetType("HomeWork.SqlHelper.ReflectionTest");
object objTet = Activator.CreateInstance(type);
//objTet.Show();
MethodInfo Show1 = type.GetMethod("Show1");
object oResutl1 = Show1.Invoke(objTet, new object[] {
});
object oResutl = Show1.Invoke(objTet, new object[0]);
MethodInfo Show2 = type.GetMethod("Show2");
object oResutl2 = Show2.Invoke(objTet, new object[] {
123 });
//Console.WriteLine("*********************Reflection调用普重载方法*************************");
MethodInfo Show33 = type.GetMethod("Show3",new Type[] {
typeof(DateTime)});
object oResutl33 = Show33.Invoke(objTet, new object[] {
DateTime.Now });
Console.WriteLine($"{ typeof(DateTime) }>>>>>oResutl33执行完的参数值{oResutl33}");
MethodInfo Show3 = type.GetMethod("Show3", new Type[] {
typeof(int), typeof(string) });
object oResutl3 = Show3.Invoke(objTet, new object[] {
123, "阳光下的微笑" });
MethodInfo Show3_1 = type.GetMethod("Show3", new Type[] {
typeof(string), typeof(int) });
object oResutl3_1 = Show3_1.Invoke(objTet, new object[] {
"明日梦", 234 });
MethodInfo Show3_2 = type.GetMethod("Show3", new Type[] {
typeof(int) });
object oResutl3_2 = Show3_2.Invoke(objTet, new object[] {
345 });
MethodInfo Show3_3 = type.GetMethod("Show3", new Type[] {
typeof(string) });
object oResutl3_3 = Show3_3.Invoke(objTet, new object[] {
"赤" });
MethodInfo Show3_4 = type.GetMethod("Show3", new Type[0]);
object oResutl3_4 = Show3_4.Invoke(objTet, new object[] {
});
Console.WriteLine("*********************Reflection调用私有方法*************************");
MethodInfo Show4 = type.GetMethod("Show4", BindingFlags.NonPublic | BindingFlags.Instance);
object oResutl4 = Show4.Invoke(objTet, new object[] {
"伟文" });
MethodInfo Show5 = type.GetMethod("Show5", BindingFlags.Static | BindingFlags.Public);
object oResutl5 = Show5.Invoke(objTet, new object[] {
"追逐梦想的人。。" });
object oResutl5_1 = Show5.Invoke(null, new object[] {
"you。。" });
}
5.反射调用泛型类+泛型方法
Console.WriteLine("*********************Reflections实例化泛型类+调用泛型方法*************************");
{
GenericMethod genericMethod = new GenericMethod();
genericMethod.Show<int, string, DateTime>(123, "黄大仙", DateTime.Now);
Assembly assembly3 = Assembly.LoadFrom("HomeWork.SqlHelper.dll"); //dll名称(需要后缀)
Type type = assembly3.GetType("HomeWork.SqlHelper.GenericMethod");
object genericTest = Activator.CreateInstance(type);
MethodInfo show = type.GetMethod("Show");
//注意:需要指定泛型方法的泛型类型
MethodInfo show1 = show.MakeGenericMethod(new Type[] {
typeof(int), typeof(string), typeof(DateTime) });
show1.Invoke(genericTest, new object[] {
123, "黄大仙", DateTime.Now });//如果是泛型方法,需要先确定类型,再执行方法,注意:指定的类型和传入的参数类型必须匹配
}
//泛型类
{
Assembly assembly3 = Assembly.LoadFrom("HomeWork.SqlHelper.dll"); //dll名称(需要后缀)
Console.WriteLine(typeof(GenericClass<,,>));
//下面的方法未能成功获取到原因由于它是泛型类。要在声明类的时候就告知参数类型
//Type type = assembly3.GetType("HomeWork.SqlHelper.GenericClass`3");
//MethodInfo show = type.GetMethod("Show");
//MethodInfo show2 = show.MakeGenericMethod(new Type[] { typeof(DateTime), typeof(int), typeof(string) });
Type type = assembly3.GetType("HomeWork.SqlHelper.GenericClass`3");
Type type1 = type.MakeGenericType(new Type[] {
typeof(int), typeof(string), typeof(DateTime) });
object genericObj = Activator.CreateInstance(type1);
MethodInfo show1 = type1.GetMethod("Show");
show1.Invoke(genericObj, new object[] {
234, "工程师 冯", DateTime.Now });
//GenericClass genericClass = new DB.SqlServer.GenericClass();
GenericClass<int, string, DateTime> genericClass = new GenericClass<int, string, DateTime>();
genericClass.Show(234, "工程师 冯", DateTime.Now);
}
6.反射的性能问题
- 大家可以通过Stopwatch来监视下获取动态库再到被实例过程需要的时间。可以通过循环来测试。
- 经测试确实发现反射会带来性能问题。但是仅在获取动态库与创建对象时耗时比较大。
- 但是是在循环很多次的情况。这种可以通过代码优化来避免。比如。根本不会在循环里获取那么多次对象。把获取对象放在循环外就可以了。
- 这样速度差异就可以忽略不计了。
老师讲的一些好处
//解耦:去掉对细节的依赖
//如果你们的公司来了一个新的技术经理;说要搞MySql
//反射来做,
// 1.仅仅只需要实现MySqlHelper,
// 2.Copy Dll文件
// 3.修改配置文件
//把数据库的版本给更换了
//实现了程序的可配置;程序的课扩展;
//反射破坏单例
//反射可以突破方法的权限限制;
7.反射在框架中的应用
反射:IOC
反射应用于哪些框架;
IOC框架;反射+配置文件+工厂==IOC框架中应用;
反射--MVC
dll: HomeWork.SqlHelper.dll
type: HomeWork.SqlHelper.GenericDouble
就可以创建对象
type可以获取到Method===Method名称--字符串
dll名称+类名称+方法名称===可以调用这个方法
localhost://Home/Index/123== 可以调用到MVC项目中的某一个Action,你们觉得这是用的什么技术?
MVC中调用方法就是反射的真实写照。。
反射在ORM中的应用:
ORM---对象关系映射,就是通过对类的达成对数据库的操作;
方法、属性、字段
8.封装ORM数据库访问
//控制台程序
{
SqlServerHelper sqlServerHelper = new SqlServerHelper();
//Company company = sqlServerHelper.QueryCompany(1);
Company company = sqlServerHelper.Find<Company>(1);
User user = sqlServerHelper.Find<User>(1);
Console.WriteLine(company);
Console.WriteLine(user);
}
//SqlServerHelper中的方法,通过反射结合泛型就能实现数据的查询。经过小扩展可以实现删除与添加数据。
public T Find<T>(int id) where T : BaseModel
{
string constr = "server=.;database=CustomerDB;uid=sa;pwd=sasa";
Type type = typeof(T);
object oResult = Activator.CreateInstance(type);
var propList = type.GetProperties().Select(p => $"[{p.Name}]");
string props = string.Join(",", propList);
string sql = $"select {props} from [{type.Name}] where id={id}";
using (SqlConnection con = new SqlConnection(constr)) {
using (SqlCommand command=new SqlCommand())
{
command.Connection = con;
command.CommandText = sql;
con.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
foreach (PropertyInfo prop in type.GetProperties())
{
prop.SetValue(oResult, reader[prop.Name]);
}
}
}
}
return oResult as T;
}