1.What?反射是什么?
反射:无处不在,MVC,Webfrom,asp.net,ORM,IOC,AOP,几乎所有的框架都离不开反射,那么反射到底是什么?
我们写的代码,计算机要识别,需要二次编译,中间会经过编译器编译,得到dll,exe,再被JIT编译最终被计算机语言识别,执行,那dll,exe是怎么生成的呢?
生成的exe还可以直接打开执行
那这个exe里面具体是什么呢?我们可以用反编译工具打开看看,打开就可以看到我们反编译以后的IL:也是一种面向对象语言,但是不太好阅读
反射Reflection:system.Reflection,其实就是.net.fromwork提供的一个帮助内库,可以读取并使用metadata
那我们如何去读取信息呢?
2.用反射加载和读取信息[三种方式]
我们先随便写个接口类:新建-DB.Interface类库,新建一个接口类IDBHelper
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace DB.Interface 8 { 9 // DB.Interface接口类库 10 public interface IDBHelper 11 { 12 void Query(); 13 } 14 }
再新建一个DB.MySql类库,新建一个MySqlHelper类继承接口IDBHelper
using DB.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DB.MySql { public class MySqlHelper : IDBHelper { /// <summary> /// MySqlHelper构造函数 /// </summary> public MySqlHelper() { Console.WriteLine("{0}被构造", this.GetType().Name); } /// <summary> /// Query方法 /// </summary> public void Query() { Console.WriteLine("{0}.Query",this.GetType().Name); } } }
按照上面的步骤,新建一个DB.SqlServer类库,新建一个SqlServerHelper类继承接口IDBHelper
using DB.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DB.SqlServer { /// <summary> /// SqlServer实现 /// </summary> public class SqlServerHelper : IDBHelper { /// <summary> /// SqlServerHelper构造函数 /// </summary> public SqlServerHelper() { Console.WriteLine("{0}被构造",this.GetType().Name); } /// <summary> /// Query方法 /// </summary> public void Query() { Console.WriteLine("{0}.Query",this.GetType().Name); } } }
#region Reflecgion { Console.WriteLine("---------------------------------------------反射加载和读取信息---------------------------------------------------------"); //动态加载 都是把dll加到内存里面去,不需要向上面的普通方法一样引用 //1.一个完整的dll名称,不需要后缀,目的:把dll加载到内存中间去; //缺陷:但是有个限制从编译以后生成的exe所在的路径去查找,既可以找dll,又可以找exe,两个一样得话先找dll【常用】 Assembly assembly = Assembly.Load("DB.MySql"); //2.还有一种加载方式,path,需要一个完整的路径,性能差不多,也可以切换为别的引用了的路径【全名称= 全路径+dll名称 + 后缀】 Assembly assembly1 = Assembly.LoadFile(@"F:LearnTestMyReflectionFirstMyReflectionFirstinDebugDB.MySql.dll"); //3.loadfrom:带后缀的,当前路径查找,也可以全路径 Assembly assembly2 = Assembly.LoadFrom("DB.MySql.dll");//【当前路径+ 后缀】 Assembly assembly3 = Assembly.LoadFrom(@"F:LearnTestMyReflectionFirstMyReflectionFirstinDebugDB.MySql.dll"); //读取里面的信息 foreach (var types in assembly.GetTypes())//GetTypes 获取此程序集中的全部类型 { Console.WriteLine(types.Name);
//type.IsGenericType //判断当前是否是泛型类 foreach (var method in types.GetMethods())//返回为GetMethods的所有公共方法 { Console.WriteLine(method.Name); } } } #endregion
我们跟踪就可以看到利用反射加载出来的一些基本信息
3.反射使用信息
#region Common { Console.WriteLine("---------------------------------------------Common---------------------------------------------------------"); { //添加接口引用,内库引用,实例化并且调用方法 IDBHelper dBHelper = new MySqlHelper(); dBHelper.Query(); } } #endregion
#region Reflecgion { Console.WriteLine("---------------------------------------------用反射使用信息---------------------------------------------------------"); //1.动态加载 Assembly assembly = Assembly.Load("DB.MySql"); // 第一步我们会获取到全部的类型,也可以指定获取类型【完整类型名称】 Type type = assembly.GetType("DB.MySql.MySqlHelper"); //3.实例化 // 意思跟Activator.CreateInstance(type);差不多都是实例化new MySqlHelper();但是这边创建的实例是个object类型 object oDBHelper=Activator.CreateInstance(type); //很确定oDBHelper里面有Query这个方法Why不能直接调用方法?编译器不认可,不能直接调用 //c#是一门强类型语言,静态语言,编译时就确定好了类型确保安全 //oDBHelper.Query() //dynamic可以是因为它很特殊编译器不检查,运行时才检查 //dynamic dDBHelper = Activator.CreateInstance(type); //dDBHelper.Query(); //4.类型转换,类型不对会直接返回null IDBHelper dBHelper = oDBHelper as IDBHelper; //5.方法调用 dBHelper.Query(); } #endregion
那么问题来了我只需要用普通方法两句话写完的,我们为什么要用反射要写5句???何必呢?意义何在?
我们就上面的代码先来封装一下看看:
1 <configuration> 2 <startup> 3 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> 4 </startup> 5 <appSettings> 6 <!--以英文逗号","分开--> 7 <add key="IDBHelperConfig" value="DB.MySql.MySqlHelper,DB.MySql"/> 8 </configuration>
namespace MyReflectionFirst { public class SingleFactory { /// <summary> /// private避免被人可以看到,static静态,会在程序第一次调用的时候读取,只读一遍 /// </summary> private static string IDBHelperConfig = ConfigurationManager.AppSettings["IDBHelperConfig"].ToString(); private static string TypeName = IDBHelperConfig.Split(',')[0]; private static string DLLName = IDBHelperConfig.Split(',')[1]; public static IDBHelper CreateInstance() { Assembly assembly = Assembly.Load(DLLName); Type type = assembly.GetType(TypeName); object oDBHelper = Activator.CreateInstance(type); IDBHelper dBHelper = oDBHelper as IDBHelper; return dBHelper; } } }
那我们再来调用看看:
{ Console.WriteLine("-------------------------------------Reflecgion+Factory+Config-------------------------------------------------"); IDBHelper dBHelper = SingleFactory.CreateInstance(); dBHelper.Query(); }
这是普通方法和反射封装完成调用 的结果以及代码对比,从调用上是不是差不多了呢?
我们再进一步对比延伸扩展一下:
如果我们需要更换一下版本呢?
普通方法:【就必须重新引用,修改代码,重新编译发布】
//如果从MySqlHelper换成SqlServerHelper,就必须重新引用,修改代码,重新编译发布 IDBHelper dBHelper = new SqlServerHelper(); dBHelper.Query();
而我们的反射,只需修改配置文件即可:
<add key="IDBHelperConfig" value="DB.SqlServer.SqlServerHelper,DB.SqlServer"/>
结果:
那要是我们要新增一个以前没有的Oracle版本:
按照上面的步骤,新建一个DB.Oracle类库,新建一个OracleHelper类继承接口IDBHelper
using DB.Interface; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DB.Oracle { public class OracleHelper : IDBHelper { public OracleHelper() { Console.WriteLine("{0}被构造",this.GetType().Name); } public void Query() { Console.WriteLine("{0}.Query",this.GetType().Name); } } }
用反射,通过修改配置文件就可以达到以下结果:
<add key="IDBHelperConfig" value="DB.Oracle.OracleHelper,DB.Oracle"/>
结果:
//特点:动态扩展性太强 //可配置可扩展:完全不修改原有代码,只是增加新的实现,copy,修改配置文件,就可以支持新功能 //原理:反射的动态加载和动态创建对象,以及配置文件结合 //可以支持随机换,也可以后面新增 //前提:实现类必须是事先已有的,而且在目录下面的
4.反射的使用
上面我们用反射获取了无参数的构造函数,那么我们怎么去获取有参数的构造函数呢?我们怎么去获取构造函数参数,以及类型,调用?
让我们看一个例子,在DB.SqlServer类库中,新建一个ReflecgionTest类
public class ReflecgionTest { #region Identity public ReflecgionTest() { Console.WriteLine("这是{0}无参数构造函数", this.GetType()); } public ReflecgionTest(string name) { Console.WriteLine("这是{0}有参数构造函数", this.GetType()); } public ReflecgionTest(int id) { Console.WriteLine("这是{0}有参数构造函数", this.GetType()); } #endregion }
{ Console.WriteLine("-----------------------------------ctor¶meter---------------------------------------------------"); Assembly assembly = Assembly.Load("DB.SqlServer"); Type type = assembly.GetType("DB.SqlServer.ReflecgionTest"); //获取构造函数 foreach (ConstructorInfo ctor in type.GetConstructors())//循环访问集合或数组的名称 { Console.WriteLine(ctor.Name); //获取构造函数参数 foreach (var parameter in ctor.GetParameters()) { //获取构造函数参数类型 Console.WriteLine(parameter.ParameterType); } } //怎么为不同的构造函数指定不同的参数类型 //object test1 = Activator.CreateInstance(type); //object test2 = Activator.CreateInstance(type, "123"); //object test3 = Activator.CreateInstance(type, 123); //应用建议改为以下写法 object test4 = Activator.CreateInstance(type, new object[] { "123" }); object test5= Activator.CreateInstance(type, new object[] { 123}); }
结果:
5.反射-黑科技:反射破坏单例
让我们看一个例子,在DB.SqlServer类库中,新建一个Singleton类
namespace DB.SqlServer { /// <summary> /// 单例模式:就是一个类,保证在整个进程中就只有一个实例 /// </summary> public sealed class Singleton { //3.当然这个实例只能有一个,所以我们提供了一个静态字段, private static Singleton _singleton = null; //1.构造函数私有化,才不能随便new,才能保证只有一个对象 private Singleton() { Console.WriteLine("{0}被构造",this.GetType().Name); } //4.这个字段只能初始化一次,那怎么初始化?我们交给了这个静态构造函数,它由CLR保障,在程序启动的第一次调用这个类Singleton之前完成的调用,而且只调用一次 static Singleton() { _singleton = new Singleton(); } //2.私有化了之后,对外不能new,但我可以对外提供一个公开的静态方法,负责提供这个对象的实例,可以调用这个方法获取这个实例,那怎么获取? public static Singleton GetInstance() { return _singleton; } } }
{ Console.WriteLine("-----------------------------------扩展:未使用反射之前的单例调用---------------------------------------------------"); //Singleton singleton = new Singleton();//私有化不能直接构造 Singleton singleton1 = Singleton.GetInstance(); Singleton singleton2 = Singleton.GetInstance(); Singleton singleton3 = Singleton.GetInstance(); Console.WriteLine($"{Object.ReferenceEquals(singleton1, singleton3)}");//不管有几个实例,结果肯定为True,因为都是同一个对象,只会被构造一次 }
{ Console.WriteLine("-----------------------------------扩展:反射破坏单例---反射调用私有构造函数---------------------------------------------------"); Assembly assembly = Assembly.Load("DB.SqlServer"); Type type = assembly.GetType("DB.SqlServer.Singleton"); //Singleton singletonA=(Singleton)Activator.CreateInstance(type);//类型转换 //如上写法会报错,因为上面我们说过它相当于一个实例化,但是这个构造函数私有化,不能直接New Singleton singletonA = (Singleton)Activator.CreateInstance(type,true);//但是反射做到了这件事 //Why这个地方执行了第一次使用的时候会执行两遍构造函数,程序在一次使用这个类的时候就会去完成静态构造函数的构造,程序在每次使用都会再去构造一次 Singleton singletonB = (Singleton)Activator.CreateInstance(type, true); Singleton singletonC = (Singleton)Activator.CreateInstance(type, true); //nonPublic:如果公共或非公共默认构造函数可以匹配,则为true;如果只有公共默认构造函数可以匹配,则为false。 //所以对象是不一样的,对象被构造了多次 Console.WriteLine($"{Object.ReferenceEquals(singletonA,singletonC)}"); }
结果对比:
六.反射调用泛型类与方法
让我们看一个例子,在DB.SqlServer类库中,新建一个GenericTest类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DB.SqlServer { public class GenericTest<T,W,X> { public void Show(T t, W w,X x) { Console.WriteLine("This's t.type={0},w.type={1}, x.type={2}", t.GetType().Name,w.GetType().Name,x.GetType().Name); } } public class GenericMethod { public void Show<T, W, X>(T t, W w, X x) { Console.WriteLine("This's t.type={0},w.type={1}, x.type={2},t:{3},w:{4},x:{5}", t.GetType().Name, w.GetType().Name, x.GetType().Name, t, w, x); } } public class GenericDouble<T> { public void Show<W, X>(T t, W w, X x) { Console.WriteLine("This's t.type={0},w.type={1}, x.type={2},t:{3},w:{4},x:{5}", t.GetType().Name, w.GetType().Name, x.GetType().Name,t,w,x); } } }
{ Console.WriteLine("-----------------------------------扩展:反射和泛型---------------------------------------------------"); Assembly assembly = Assembly.Load("DB.SqlServer"); Type type = assembly.GetType("DB.SqlServer.GenericTest"); Object oGeneric = Activator.CreateInstance(type); }
按照之前的操作,我们发现这边得到的type=null?Why?
//原因:因为public class GenericTest<T,W,X>它是泛型编译之后会变为DB.SqlServer.GenericTest`3<T, W, X>【反编译工具也可以看到】
// 我们需要把它修改为: Type type = assembly.GetType("DB.SqlServer.GenericTest`3");
跟踪结果已经找到了我们要的数据了:
再执行,报错了,类型找到了,为什么它不能创建这个实例?它不是有个无参数构造函数吗?为什么没能创建一个实例?
那这代码现在应该如何修改呢?
//在泛型类型时,不能忘记我们创建对象,它是不能够实例化的,【eg:GenericTest genericTest=new GenericTest()】那肯定是不行的 //起码你得指定好类型才能够实例化【eg:GenericTest<int, string, DateTime> genericTest = new GenericTest<int, string, DateTime>();】那应该怎样写呢? Type typeMake = type.MakeGenericType(new Type[] {typeof(int),typeof(string),typeof(DateTime) }); //泛型类是一个不确定类型的,这句话就表示我把类型确定一下,你要什么参数类型,这边是个type数组,new Type[] {}数组 Object oGeneric = Activator.CreateInstance(typeMake);//只有这个typeMake才可以创建,这边不能强制转换,因为需要类型
跟踪的结果:
如果反射创建对象之后,知道方法名称,怎么样不做类型转换,直接调用方法?让我们直接下面的实例吧
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DB.SqlServer { public class ReflecgionTest { #region Identity public ReflecgionTest() { Console.WriteLine("这是{0}无参数构造函数", this.GetType()); } public ReflecgionTest(string name) { Console.WriteLine("这是{0}有参数构造函数", this.GetType()); } public ReflecgionTest(int id) { Console.WriteLine("这是{0}有参数构造函数", this.GetType()); } #endregion #region Method /// <summary> /// 无参方法 /// </summary> public void Show1() { Console.WriteLine("这里是{0}的Show1", this.GetType()); } /// <summary> /// 有参数方法 /// </summary> /// <param name="id"></param> public void Show2(int id) { Console.WriteLine("这里是{0}的Show2", this.GetType()); } /// <summary> /// 重载方法之一 /// </summary> /// <param name="id"></param> /// <param name="name"></param> public void Show3(int id, string name) { Console.WriteLine("这里是{0}的Show3,id:{1},string:{2}", this.GetType(),id,name); } /// <summary> /// 重载方法之二 /// </summary> /// <param name="name"></param> /// <param name="id"></param> public void Show3(string name, int id) { Console.WriteLine("这里是{0}的Show3_2,string:{1},id:{2}", this.GetType(),name,id); } /// <summary> /// 重载方法之三 /// </summary> /// <param name="id"></param> public void Show3(int id) { Console.WriteLine("这里是{0}的Show3_3,id:{1}", this.GetType(),id); } /// <summary> /// 重载方法之四 /// </summary> /// <param name="name"></param> public void Show3(string name) { Console.WriteLine("这里是{0}的Show3_4,name:{1}", this.GetType(),name); } /// <summary> /// 重载方法之五 /// </summary> public void Show3() { Console.WriteLine("这里是{0}的Show3_1", this.GetType()); } /// <summary> /// 私有方法 /// </summary> /// <param name="name"></param> private void Show4(string name) { Console.WriteLine("这里是{0}的Show4_私有方法调用", this.GetType()); } /// <summary> /// 静态方法 /// </summary> /// <param name="name"></param> public static void Show5(string name) { Console.WriteLine("这里是{0}的Show5_静态方法调用", typeof(ReflecgionTest)); } #endregion } }
反射调用:无参数,有参数,重载,静态,私有方法实例
{ Console.WriteLine("如果反射创建对象之后,知道方法名称,怎么样不做类型转换,直接调用方法?"); Assembly assembly = Assembly.Load("DB.SqlServer"); Type type = assembly.GetType("DB.SqlServer.ReflecgionTest"); Object test = Activator.CreateInstance(type); //主要是查看它里面的所有方法名,参数,参数类型 foreach (var metohd in type.GetMethods()) { Console.WriteLine(metohd.Name+":"); foreach (var parameter in metohd.GetParameters()) { Console.WriteLine($"{parameter.Name},{parameter.ParameterType.Name}"); } } //反射调用无参数的方法 { MethodInfo methodInfo = type.GetMethod("Show1"); methodInfo.Invoke(test, null);//第一个参数表示实例,后一个参数列表 } //反射调用带参数的方法 { MethodInfo methodInfo1 = type.GetMethod("Show2"); methodInfo1.Invoke(test, new object[] { 123 }); } //重载方法调用 { MethodInfo method=type.GetMethod("Show3",new Type[] { typeof(string),typeof(int)}); method.Invoke(test, new object[] { "现在是哪一年", 2020}); } { MethodInfo method = type.GetMethod("Show3",new Type[] { typeof(int),typeof(string)}); method.Invoke(test, new object[] { 2020, "year" }); } { MethodInfo method = type.GetMethod("Show3",new Type[] { typeof(int)}); method.Invoke(test, new object[] { 2020 }); } { MethodInfo method = type.GetMethod("Show3",new Type[] { typeof(string)}); method.Invoke(test, new object[] { "wang" }); } { MethodInfo method = type.GetMethod("Show3",new Type[] { }); method.Invoke(test, null); } //静态方法【特别】:实例可以要,也可以不要【null】 { MethodInfo method = type.GetMethod("Show5"); method.Invoke(null,new object[] { "你好"}); } { MethodInfo method = type.GetMethod("Show5"); method.Invoke(test, new object[] { "你好" }); } {//反射调用私有方法 var method = type.GetMethod("Show4", BindingFlags.Instance | BindingFlags.NonPublic); method.Invoke(test, new object[] { "私有方法调用" }); } }
结果:
那么泛型的方法又如何用反射调用呢?
{ Console.WriteLine("-----------------------------------扩展:泛型方法GenericMethod---------------------------------------------------"); Assembly assembly = Assembly.Load("DB.SqlServer"); Type type = assembly.GetType("DB.SqlServer.GenericMethod"); Object oGeneric = Activator.CreateInstance(type); MethodInfo method = type.GetMethod("Show");//泛型方法不用Show`3 var methodnew=method.MakeGenericMethod(new Type[]{ typeof(int),typeof(string), typeof(DateTime)}); methodnew.Invoke(oGeneric, new object[] { 12, "泛型方法 ", DateTime.Now }); }
结果:
泛型方法和泛型类同时存在的情况:
{ Console.WriteLine("扩展:泛型类+泛型方法GenericMethod"); Assembly assembly = Assembly.Load("DB.SqlServer"); Type type = assembly.GetType("DB.SqlServer.GenericDouble`1").MakeGenericType(new Type[] { typeof(int) }); Object oObject=Activator.CreateInstance(type); MethodInfo method = type.GetMethod("Show").MakeGenericMethod(new Type[] {typeof(string),typeof(DateTime) }); method.Invoke(oObject,new object[] { 2020,"hello",DateTime.Today}); }
结果:
七:反射的应用:
获取全部的实体的全部属性并给其赋值:
//实体类不考虑扩展问题,没意义 Console.WriteLine("---------------------------------------------Reflection---------------------------------------------------------"); Type type = typeof(People); Object opeople=Activator.CreateInstance(type); //获取全部的属性 foreach (var prop in type.GetProperties()) { Console.WriteLine($"{type.Name}.{prop.Name}={prop.GetValue(opeople)}"); //给prop里面的属性增加一个值 if (prop.Name.Equals("Id")) { prop.SetValue(opeople, 1); } else if(prop.Name.Equals("Name")) { prop.SetValue(opeople, "泛型实体属性"); } Console.WriteLine($"{type.Name}.{prop.Name}={prop.GetValue(opeople)}"); } foreach (var field in type.GetFields()) { Console.WriteLine($"{type.Name}.{field.Name}={field.GetValue(opeople)}"); if (field.Name.Equals("Description")) { field.SetValue(opeople, "只是一个字段"); } Console.WriteLine($"{type.Name}.{field.Name}={field.GetValue(opeople)}"); }
//思考:反射对实体层的操作如此麻烦,Why我们还要用它?eg:让我们一起看一个场景:
public Company FindOld(int Id) { string sql = @"SELECT [Id] ,[Name] ,[CreateTime] ,[CreatorId] ,[LastModifierId] ,[LastModifyTime] FROM [Company] where Id="+Id; //[Name],[CreateTime],[CreatorId],[LastModifierId],[LastModifyTime],[Id] using (SqlConnection con = new SqlConnection(ConnectionStringCustomers)) { SqlCommand sqlCommand = new SqlCommand(sql, con); con.Open(); var reader=sqlCommand.ExecuteReader(); if (reader.Read())//有数据才开始读,有数据True { Console.WriteLine(reader[1]); } con.Close(); con.Dispose(); } return new Company(); }
现在只有一个表,我们还有一个表,那如果我们有很多表,那岂不是都需要写很多方法, 如果我们希望一个方法,能返回不同的类型,针对以上代码优化:
/// <summary> /// 如果我们希望一个方法,能返回不同的类型?泛型+反射【不同类型,不同sql】, /// </summary> public T Find<T>(int Id) { Type type = typeof(T); //type.GetProperties().Select(p=> p.Name)得到属性名称, //type.GetProperties().Select(p => $"[{p.Name}]")得到它的属性名称并写出如下格式:[CreatorId]*/ //得到的是一个集合,需要把它变成一个逗号连接的字符串 //得到它的属性名称,把它变成一个逗号连接的字符串 string prop = string.Join(",", type.GetProperties().Select(p => $"[{p.Name}]")); //动态拼接Sql string sql = $"select {prop} from [{type.Name}] where ID={Id}"; Object oObject = Activator.CreateInstance(type); //如果是User表User在数据库里面属于关键字,[{type.Name}]类似FROM [User] using (SqlConnection con = new SqlConnection(ConnectionStringCustomers)) { SqlCommand sqlCommand = new SqlCommand(sql, con); con.Open(); var reader = sqlCommand.ExecuteReader(); if (reader.Read())//有数据才开始读,有数据True { //获取所有的属性进行赋值 foreach (var propinfo in type.GetProperties()) { //针对数据库名跟实力类名一一对应的场景 propinfo.SetValue(oObject, reader[propinfo.Name] is DBNull ? null : reader[propinfo.Name]); } return (T)oObject; } else { return default; } } }
调用:
{ SqlServerHelper sqlServer = new SqlServerHelper(); Company company = sqlServer.Find<Company>(1); User user = sqlServer.Find<User>(1); }
{ Console.WriteLine("---------------------------------------------Common---------------------------------------------------------"); People people = new People(); people.Id = 1; people.Name = "普通"; people.Description = "描述:"; Console.WriteLine($"people.Id ={people.Id}"); Console.WriteLine("people.Name = {0},people.Description={1}",people.Name,people.Description); }
//Get:反射展示是意义的,可以不用改代码,普通方法需要修改 //Set:感觉没什么用,但是还是有用,
//反射: //优点:动态,【几乎任何一个框架里面都有反射,我们搭建框架就是希望有良好的扩展性,能够应对将来任意的需求变化】 //缺点;1.使用麻烦【封装一下】;2.避开编译器检查,运行时出问题;3.性能问题;
using DB.Interface; using DB.SqlServer; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace MyReflectionFirst { public class Monitor { public static void Show() { Console.WriteLine("------------------------------Monitor普通方法与反射的性能测试--------------------------------------------"); //初始化 long ComonTime = 0; long ReflectionTime = 0; { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i < 1_000_000; i++) { IDBHelper sqlServer = new SqlServerHelper(); sqlServer.Query(); } stopwatch.Stop(); ComonTime = stopwatch.ElapsedMilliseconds; } { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Assembly assembly = Assembly.Load("DB.SqlServer"); Type type = assembly.GetType("DB.SqlServer.SqlServerHelper"); for (int i = 0; i < 1_000_000; i++) { Object oDBHelper = Activator.CreateInstance(type); IDBHelper dBHelper = oDBHelper as IDBHelper; dBHelper.Query(); } stopwatch.Stop(); ReflectionTime = stopwatch.ElapsedMilliseconds; } Console.WriteLine("ComonTime:{0}ms,ReflectionTime:{1}ms", ComonTime, ReflectionTime); //ComonTime:71ms,ReflectionTime:134ms } } }