反射由浅入深了解学习(一)
一,反射三个步骤
1, 加载dll获取的程序集
2,通过加载的dll得到的程序集和类型的全名,得到想要的类型
3,使用指定类型的默认构造函数来创建该类型的实例
二,代码结构如下图
二,Program.cs代码如下:
using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace ReflectionDemo { class Program { private static string config = ConfigurationManager.AppSettings["DbConfig"]; //反射的配置 static void Main(string[] args) { Assembly assembly = Assembly.Load(config.Split(',')[1]); //加载dll获取的程序集 Type type = assembly.GetType(config.Split(',')[0]); //通过加载的dll得到的程序集和类型的全名,得到想要的类型 //显示加载程序集的路径 foreach (Module item in assembly.GetModules()) { Console.WriteLine("DLL地址{0}", item.FullyQualifiedName); } ///显示加载程序集的名称 foreach (Type item in assembly.GetTypes()) { Console.WriteLine("DLL名称{0}", item.FullName); } ///显示所有方法 foreach (MethodInfo item in type.GetMethods()) { Console.WriteLine("方法名称{0}", item.Name); } //创建对象,使用指定类型的默认构造函数来创建该类型的实例 object oDbHelper = Activator.CreateInstance(type); ///反射调用无参数方法 ///PS修改BLL库需要拷贝到当前的控制台程序 MethodInfo query1 = type.GetMethod("Query"); query1.Invoke(oDbHelper, null); //发现不明确匹配,因为Query1方法重载了,跟MVC中的找视图和方法时报错一样,多个请求路由存在多个相同命名视图逻辑一样报错 //MethodInfo query8 = type.GetMethod("Query1"); //query8.Invoke(oDbHelper, new object[] { "string参数" }); ///反射带参数方法 MethodInfo query2 = type.GetMethod("Query1", new Type[] { typeof(string) }); query2.Invoke(oDbHelper, new object[] { "string参数" }); MethodInfo query3 = type.GetMethod("Query1", new Type[] { typeof(int) }); query3.Invoke(oDbHelper, new object[] { 111 }); /// PS:对私有方法和静态实例不建议用反射来获取实现,破坏了设计的原则,但是测试和观看源码时可以使用 //私有方法的反射 MethodInfo query4 = type.GetMethod("QueryPrivate", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); query4.Invoke(oDbHelper, null); //私有带参数方法的反射 MethodInfo query5 = type.GetMethod("QueryPrivateParam", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(int) }, null); query5.Invoke(oDbHelper, new object[] { 444 }); MethodInfo query6 = type.GetMethod("QueryPrivateParam", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null); query6.Invoke(oDbHelper, new object[] { "string参数" });
//对单例模式创建实例
//Type Singleton = assembly.GetType("BLLExt.Singleton");
////object ob = Activator.CreateInstance(Singleton); //报错:没有为该对象定义无参数的构造函数
//object ob = Activator.CreateInstance(Singleton,true);
Console.ReadKey();
}
}
}
SqlHelper.cs代码如下:
using IBLL; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace BLL { public class SqlHelper: IDbHelper { public SqlHelper() { Console.WriteLine("{0}被构造", this.GetType().Name); } public void Query() { Console.WriteLine("{0}.Query", this.GetType().Name); } public void Query1(string obj) { Console.WriteLine("{0}---{1}.Query", obj, this.GetType().Name); } public void Query1(int obj) { Console.WriteLine("{0}---{1}.Query", obj, this.GetType().Name); } private void QueryPrivate() { Console.WriteLine("{0}.QueryPrivate", this.GetType().Name); } private void QueryPrivateParam(string obj) { Console.WriteLine("{0}---{1}.QueryPrivateParam", obj, this.GetType().Name); } private void QueryPrivateParam(int obj) { Console.WriteLine("{0}---{1}.QueryPrivateParam", obj, this.GetType().Name); } } }
IDbHelper.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IBLL { public interface IDbHelper { void Query(); } }
App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> <add key="DbConfig" value="BLL.SqlHelper,BLL"/> <!--<add key="DbConfig" value="BLLExt.MySqlHelper,BLLExt"/>--> </appSettings> </configuration>
三,如上代码,我们需要注意的是:
1,创建反射的步骤
2,反射调用无参数方法和有参方法的区别
3,重载方法的反射需标明参数的类型,如下:
//发现不明确匹配,因为Query1方法重载了,跟MVC中的找视图和方法时报错一样,多个请求路由存在多个相同命名视图逻辑一样报错 MethodInfo query8 = type.GetMethod("Query1"); query8.Invoke(oDbHelper, new object[] { "string参数" });
以上报错,重载方法无参数正确写法
//重载方法无参数反射的使用 MethodInfo query9 = type.GetMethod("Query1", new Type[] { }); query9.Invoke(oDbHelper, null);
4,对私有方法的反射
四,反射的扩展
1,对单例的反射
Singleton.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace BLL { public class Singleton { public static Singleton _Instance = new Singleton(); private Singleton() { Console.WriteLine("{0}被构造了",this.GetType().Name); } } }
反射代码
//对单例模式创建实例 Type Singleton = assembly.GetType("BLLExt.Singleton"); ////object ob = Activator.CreateInstance(Singleton); //报错:没有为该对象定义无参数的构造函数 object ob = Activator.CreateInstance(Singleton,true);
2,反射类库的切换,通过反射获取的实例都是不需要引用的,如下图,没有引用bll
那我们怎么动态切换库呢?再用反射时只需要更改配置文件App.config即可,如配置
更改配置为,BLLExt.MySqlHelper,输出结果是不一样的
PS :但是每次我们修改BLL和BLLExt库时都要将其生成的DLL手动拷贝到ReflectionDemo的bin文件下,原因是:ReflectionDemo没有引用这两个库,重新生成不会生成到改目录的bin目录下