反射概念:反射是由框架提供的一个类库,可以访问dll的metadata,获取的dll的信息,并使用它
反射的命名空间:using System.Reflection;
DLL里面包含了两种:
1.IL中间语言,最后变成机器码
2.metadata元数据,用于描述IL
程序结构:
Reflence引用DB.sqlserver DB.interface
DB.sqlserver引用DB.interface
接口配置:
普通实现方法:实例化
IDBserver dBserver =newsqlserverDBhelper(); dBserver.Query();
效果
利用反射去实现:
//Assembly是反射的命名空间引入的类 Assembly assembly = Assembly.Load("DB.sqlserver");//动态加载dll没有后缀 Type type = assembly.GetType("DB.sqlserver.sqlserverDBhelper");//获取类型名称 传递完整类型 Object obj = Activator.CreateInstance(type);//创建对象 ((sqlserverDBhelper)obj).Query();//调用方法 Console.ReadLine();
如果每增加一个类就要重新指定DLL名称,配置性不高
为了增加程序的可配置性,新建一个工厂类
如果程序需要读取配置文件就需要引入一个DLL
引入命名空间 using System.Configuration;
配置文件添加,键值对
<appSettings> <add key="IDBHelperType" value="DB.sqlserver,DB.sqlserver.sqlserverDBhelper"></add> </appSettings>
publicclassObjectFactroy { //根据key名字获取,读取到当前项 privatestatic string IDBHelperType = ConfigurationManager.AppSettings["IDBHelperType"]; publicstatic string DLLName = IDBHelperType.Split(',')[0];//获取DLL名称 publicstatic string TypeName = IDBHelperType.Split(',')[1];//获取文件名 publicstatic IDBserver CreateInstance() { Assembly assembly = Assembly.Load(DLLName); Type type = assembly.GetType(TypeName);//获取类型名称 传递完整类型 Object obj = Activator.CreateInstance(type);//创建对象 return(IDBserver)obj; } }
有需要变更直接在配置文件更改value值
Main 函数调用
IDBserver bserver = ObjectFactroy.CreateInstance(); bserver.Query();
1.怎样让程序可配置可扩展呢,在不改变原来代码的条件下增加一个类库
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using DB.Interface; namespace DB.Oracle { publicclassOracleDBhelper: IDBserver { publicOracleDBhelper() { Console.WriteLine("{0}被构造",this.GetType().Name); } publicvoidQuery() { Console.WriteLine("{0},Query",this.GetType().Name); } } }
修改配置文件指向新的DLL
上述已经配置好接口类型,第三方依赖注入的容器会帮你完成创建
实际上这就是IOC,业务逻辑层提供一个接口进行IOC的配置
此时
1.去掉接口,反射调用方法
此时调用的是Query的无参数构造方法
Assembly assembly = Assembly.Load("DB.sqlserver");//动态加载dll没有后缀 Type type = assembly.GetType("DB.sqlserver.sqlserverDBhelper");//获取类型名称 传递完整类型 Object obj = Activator.CreateInstance(type);//创建对象 MethodInfo method = type.GetMethod("Query",newType[]{}); method.Invoke(obj,newobject[]{});
仔细观察发现这也是MVC方法响应的原理,DLL在程序最初已经编译好,MVC路径:/控制器/方法。只需要指定方法就能随意跳转页面
模仿控制器传入方法的多种参数
Assembly assembly = Assembly.Load("DB.sqlserver");//动态加载dll没有后缀 Type type = assembly.GetType("DB.sqlserver.sqlserverDBhelper");//获取类型名称 传递完整类型 Object obj = Activator.CreateInstance(type);//创建对象 { { MethodInfo method = type.GetMethod("Query",newType[]{}); method.Invoke(obj,newobject[]{}); } { MethodInfo method = type.GetMethod("Query",newType[]{typeof(string)}); method.Invoke(obj,newobject[]{"AB"}); } { MethodInfo method = type.GetMethod("Query",newType[]{typeof(int)}); method.Invoke(obj,newobject[]{20}); } { MethodInfo method = type.GetMethod("Query",newType[]{typeof(string),typeof(int)}); method.Invoke(obj,newobject[]{"AB",20}); } { MethodInfo method = type.GetMethod("Query",newType[]{typeof(int),typeof(string)}); method.Invoke(obj,newobject[]{20,"AB"}); } }
反射最大的优点:动态加载、不需要引用命名空间
缺点:编写麻烦,避开了编译器的检查不到错误
利用反射获取属性和方法
写死的方法:
People people =newPeople() { id=10, Name="YLC" }; people.Property ="字段"; Console.WriteLine("id:{0}",people.id); Console.WriteLine("Name:{0}", people.Name); Console.WriteLine("Property:{0}", people.Property);
这个时候如果增加一个属性,代码又需要修改,增加100个就要打印100 Console.WriteLine();
利用反射自带的进行实现
Type type =typeof(People); foreach(var item in type.GetProperties())//获取属性 { object obj = item.GetValue(people); Console.WriteLine("{0}:{1}",item.Name,obj); } foreach(var item in type.GetFields())//获取字段 { object obj = item.GetValue(people); Console.WriteLine("{0}:{1}", item.Name, obj); }
效果相同