.NET 反射原理及其运用
一.何谓反射
反射:是.net framework提供的一个访问metadata的帮助类库,可以获取信息并且使用
动态是反射中的最大优点。
二:反射如何使用
#region 反射的加载方式 ////获取当前路径下面的dl或者exe,不带后缀(MyReflection.exe 是编译后生成的exe执行文件),从Exe所在的路径进行查找 Assembly assembly = Assembly.Load(@"MyReflection"); //获取完整路径下面的dl或者exe,要加后缀 Assembly assemblyFrom = Assembly.LoadFrom(@"D:\MyReflection\bin\Debug\MyReflection.exe"); //获取完整路径下面的dl或者exe,要加后缀 Assembly assemblyFile = Assembly.LoadFile(@"D:\MyReflection\bin\Debug\MyReflection.exe"); foreach (var item in assembly.GetModules()) { //Modules当前的exe或者dll的名字(MyReflection.exe) Console.WriteLine(item.Name); } //当前所包含的实体类(IDBHelper,SqlServerHelper,Program) foreach (var item in assembly.GetTypes()) { foreach(var method in item.GetMethods()){ Console.WriteLine(method.Name); } Console.WriteLine(item.Name); } foreach (var item in assembly.GetCustomAttributes()) { Console.WriteLine(item.ToString()); } //获取到有多个构造函数 foreach (var ctor in type.GetConstructors()) { Console.WriteLine(ctor.GetParameters()); //获取构造函数里面的参数 foreach (var item in ctor.GetParameters()) { Console.WriteLine(item.ParameterType); } } #endregion
三.反射的应用
(一)可以利用反射 创建一个类的实例,并调用他的方法
1.创建步骤
例如:
(1).获取类型:
Type dbhelperType = assembly.GetTyp(“Ruanmou.DB.MySql.MySqlHelper”);//== 获取所需创建类型的类型信息,传参数必须传递完整类名,从命名空间开始==
(2).创建类型对应的实例对象
//用Activator.CreateInstance(类型参数)创建所需类型的实例对象
object oDBHelper = Activator.CreateInstance(dbhelperType);
(3).转换并调用方法:
用其对应的接口进行转换
IDBHelper idbhelper = oDBHelper as IDBHelper;
idbhelper.Query();
2.具体应用
在写程序的时候,需要灵活运用类的时候,可以先在配置文件中,将需要的类型配置进去,然后在程序中根据配置文件灵活的创建所需要的类型对象:举例,程序有可能需要多种数据库,MySql 和SqlServer,写底层数据库连接的时候并不知道上层需要哪个,于是可以利用在配置文件中的连接字符串中配置Provider的dll,用反射的方式在底层创建连接字符串的时候,根据上层传入的连接字符串来灵活创建底层连接Connection.
/// <summary> /// 反射得到一个对象 /// </summary> public class SimpleFactory { //读取配置文件AppSetting里面的key // <appSettings> // <add key = "DbConfig" value="MyReflection,MyReflection.MySqlServerHelper"/> //</appSettings> private static string ConfigStr = ConfigurationManager.AppSettings["DbConfig"]; private static string DllName = ConfigStr.Split(',')[0]; //命名空间 private static string TypeName = ConfigStr.Split(',')[1]; //类型要完整命名空间+类名 public static T CreateInstance<T>() { Assembly assembly = Assembly.Load(DllName); Type type = assembly.GetType(TypeName); var objectInstance = Activator.CreateInstance(type); return (T)objectInstance; //要强制转换一下,因为牵涉到编译性语言和运行时语言 } }
(二):反射调用多构造函数,调用私有构造函数(破坏单例),调用泛型类
首先创建一个实体类,包含有参无参构造函数,然后有参无参的方法,如下:
/// <summary> /// sqlServer /// </summary> public class SqlServerHelper : IDBHelper { //private SqlServerHelper() //{ // Console.WriteLine("私有构造函数"); //} //无参构造函数 public SqlServerHelper() { Console.WriteLine("公有无参构造函数"); } //传入一个int型参数的构造函数 public SqlServerHelper(int iParam) { Console.WriteLine($"int的构造函数--{iParam}"); } //传入一个string型参数的构造函数 public SqlServerHelper(string sParam) { Console.WriteLine($"string的构造函数--{sParam}"); } //传入两个参数的构造函数 public SqlServerHelper(int iParam, string sParam) { Console.WriteLine($"int和string的构造函数--int={iParam} ;string={sParam}"); } //类内部的无参方法 public void Show() { Console.WriteLine("Show"); } //类内部的Show1的无参方法 public void Show1() { Console.WriteLine("Show1的无参方法"); } //类内部的Show1的int重载方法 public void Show1(int iParam) { Console.WriteLine($"Show1的int重载--{iParam}"); } //类内部的Show1的两参重载方法 public void Show1(int iParam, string sParam) { Console.WriteLine($"Show1两参数 iparam={iParam};sParam={sParam}"); } }
1.调用上面例子类中的 有参 或者 无参构造函数
Assembly assembly = Assembly.Load("MyReflection"); //获取当前路径下面的dl或者exe,不带后缀 Type dbHelperType = assembly.GetType("MyReflection.SqlServerHelper"); //传完整名称获类型(命名空间+类名) //调用多个构造函数(有参,无参) var obSqlServerHelper = Activator.CreateInstance(dbHelperType); //无参的构造函数 Activator.CreateInstance(dbHelperType, new object[] { 11 }); //int的构造函数 Activator.CreateInstance(dbHelperType, new object[] { "testbywss" }); //调用string的构造函数 Activator.CreateInstance(dbHelperType, new object[] { 123, "testbywss" }); //调用string的构造函数
2. 调用类的私有构造函数
//私有构造函数 Type singletonType = assembly.GetType("MyReflection.Singleton"); //传入完整名称获取类型(命名空间+类名) var object1 = Activator.CreateInstance(singletonType, true); //设置成true能调用私有/公布的构造函数,如果不设置则只能调用公有构造函数
3.不必强制类型转换,调用 普通方法,静态方法,重载方法:
在利用了反射实例化对象之后,可以不需要强制类型转换,直接调用其方法
Type dbhelperType = assembly.GetTyp(“Ruanmou.DB.SqlServer.SqlServerHelper ”);
object obSqlServerHelper = Activator.CreateInstance(dbhelperType);
(1)普通方法
Type 类型 的对象,有一个方法 GetMethods方法,可以获取这个类型对象中所指定的方法,
如下:
MethodInfo methodInfo = dbhelperType.GetMethod(“Show”); //MethodInfo 类,用于描述方法
用获取到指定方法的 MethodInfo 对象 来调用方法
methodInfo.Invoke(obSqlServerHelper, null); //第一个参数:要调用方法的实例,普通方法必须实例化之后进行调用,上面已经用Activator.CreateInstance实例化了一个该Type的实例,这里将其传入,第二个参数:是方法需要的参数,如果没有则设置为null
(2) 静态方法调用
MethodInfo staticMethodInfo = dbHelperType.GetMethod(“Show5”); //调用单个普通的实例方法
== staticMethodInfo.Invoke(null, new object[] { “静态方法第一种调用方式” }); //第一个参数:是应用对象,如果是静态可以不用写;第二个参数:是方法需要的参数,如果没有则设置为null ==
staticMethodInfo.Invoke(obSqlServerHelper, new object[] { “静态方法第二种调用方式” });//重载方法调用
(3) 调用重载方法
重载方法
MethodInfo method2 = dbHelperType.GetMethod(“Show1”, new Type[] { }); //调用无参的函数
method2.Invoke(obSqlServerHelper, null);
MethodInfo method3 = dbHelperType.GetMethod(“Show1”, new Type[] { typeof(int) }); //int参数的方法
method3.Invoke(obSqlServerHelper, new object[] { 11 });
MethodInfo method4 = dbHelperType.GetMethod(“Show1”, new Type[] { typeof(int), typeof(string) }); //调用2个参数的方法,new Type[] { typeof(int), typeof(string) } 顺序一定要跟调用的方法的参数顺序保持一致
method4.Invoke(obSqlServer
4000
Helper, new object[] { 1111, “ddd” });
4:调用泛型
(1)首先要创建一个实体类如下:
#region 泛型类 public class GenericClass<T, W, F> { public void Show(T t, W w, F f) { Console.WriteLine($"t.type={t.GetType().Name};}"); } } public class GenericMethod { public void Show<T, W, X>(T t, W w, X x) { Console.WriteLine($"t.type={t.GetType().Name};"); } } public class GenericDouble<T> { public void Show<W, X>(T t, W w, X x) { Console.WriteLine($"t.type={t.GetType().Name};"); } } #endregion
(2)调用泛型方法如下
//创建泛型
Assembly assembly = Assembly.Load(“MyReflection”); //获取当前路径下面的dl或者exe,不带后缀
== 创建泛型类,创建泛型类的时候,除了写好类名,还要给占位符,以告诉系统这个类是一个泛型类,3个占位符,表示泛型类传入三个类型参数。==
Type genericType = assembly.GetType("MyReflection.GenericClass
3"); //3是泛型类需要的参数
== 在调用实例化之前,要先指定具体的泛型的类型==
Type typeGenericNew = genericType.MakeGenericType(typeof(int), typeof(int), typeof(int)); //需要指定泛型类的类型
GenericClass<int, int, int> oGeneric = (GenericClass<int, int, int>)Activator.CreateInstance(typeGenericNew);
oGeneric.Show(1, 30, 60);
Type genericType1 = assembly.GetType(“MyReflection.GenericMethod”); //普通的类
var genericMethod = Activator.CreateInstance(genericType1) as GenericMethod;
genericMethod.Show<int, string, double>(1, “1”, 2);
5:调用私有方法
//私有方法 //调用私有方法,有参数 MethodInfo method5 = dbHelperType.GetMethod("Show5", BindingFlags.NonPublic | BindingFlags.Instance); method5.Invoke(obSqlServerHelper, new object[] { 5.0 }); //私有方法,无参数 MethodInfo method6 = dbHelperType.GetMethod("Show6", BindingFlags.NonPublic | BindingFlags.Instance); method6.Invoke(obSqlServerHelper, null);
6:调用普通方法的泛型方法
//类的泛型方法调用 Type genericMethodType = assembly.GetType("MyReflection.GenericMethod"); var objectGeneric = Activator.CreateInstance(genericMethodType); MethodInfo genericMethod = genericMethodType.GetMethod("Show"); //这一步是调用泛型方法的关键,给泛型方法的参数类型指定具体类型,并告诉系统这是一个泛型方法 MethodInfo genericMethodNew = genericMethod.MakeGenericMethod(typeof(int), typeof(int));
//对泛型方法进行调用,传入的第一个参数是调用哪个实例的这个泛型方法,第二个参数是传入参数
genericMethodNew.Invoke(objectGeneric, new object[] { 1, 4 });
- 在.net中运用HTMLParser解析网页的原理和方法
- .NET运用AJAX 总结及其实例
- 团队开发项目 特点一 运用物理学反射原理
- 计算机网络原理及其运用笔记 第六周 周阳计科1班 160809232
- KVO键值观察运用及其原理
- 运用反射原理 + POI工具写一个java接口doc工具 (扫描包下接口并生成简单接口文档)
- .NET运用AJAX 总结及其实例
- Java反射及其在开发数据库上面的运用
- eclipse反射原理及运用
- SSM 实训笔记 -02- Class.forName 运用反射的原理创建对象
- 在.net中运用HTMLParser解析网页的原理和方法
- Java基础---Java---基础加强---内省的简单运用、注解的定义与反射调用、 自定义注解及其应用、泛型及泛型的高级应用、泛型集合的综合
- 在.net中运用HTMLParser解析网页的原理和方法
- 在.net中运用HTMLParser解析网页的原理和方法
- Java基础---Java---基础加强---内省的简单运用、注解的定义与反射调用、 自定义注解及其应用、泛型及泛型的高级应用、泛型集合的综合
- .NET访问数据库经典架构(运用反射给实体赋值)
- 在.net中运用HTMLParser解析网页的原理和方法
- 运用反射原理的简单工厂模式和运用反射原理从数据库里读出数据直接封装到实体集合里
- 计算机网络原理及其运用 第七周 周阳 160809232
- 在.net中运用HTMLParser解析网页的原理和方法