C#高级开发之反射(Reflection)二
C#编译运行原理 人类能识别的认识的C#高级语言 通过vs内置编译器编译 生成 dll或是exe(主要包含metadata+IL)然后dll或是exe 依赖 CLR/JIT 运行转变成 机器能识别的 机器码(010101)
经历两次编译过程把C#人类高级语言转变成机器码(010101)
1 反射定义:反射是.net框架提供帮助类库,通过反射,可以在运行时获取程序或程序集中的每一个类型(包括类,结构,委托,接口,枚举等)
的成员或是成员信息并使用(即可以获取并使用程序或程序集的matadata信息)。
1.1反射中两大类Assembly+Type类
(1)使用System.Reflection.Assembly类定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
Assembly类可以获得程序集(DLL)的信息,也可以动态的加载程序集,以及在程序集中查找类型信息,并创建该类型的实例
Assembly assembly = Assembly.Load("DB.Oracle");//从当前目录加载dll(DB.Oracle即为项目类库名称)
Assembly assembly1 = Assembly.LoadFile(@"F:\StudyProject for TEST\MyReflection\DB.Oracle\bin\Debug\DB.Oracle.dll");//指定完整路径加载 可以是别的路径 本质还是指定到具体路径的Load方法
Assembly assembly2 = Assembly.LoadFrom("DB.Oracle.dll");//完整文件名称,需要带后缀 本质还是Load方法
通过Assembly获取程序集中类
Type[] t =assembly.GetTypes();//获取指定加载进来的dll中所有的类,
Type type = assembly.GetType("DB.Oracle.MyOracleHelper");//获取指定类的type信息,单独获取某个类的信息 通过该信息可以创建出对象
(2)使用System.Type 类可以访问任何给定数据类型的信息。 对于反射起着核心的作用,但它是一个抽象的基类,Type有与每种数据类型对应的派生类,我们使用这个派生类的对象的方法、字段、属性来查找有关该类型的所有信息。
获取给定类型的Type引用有3种常用方式
1.使用C# typof运算符准对的是某一个类型 Type type = typeof(string)
2.使用对象GetType()方法 准对的是某一个变量 string s = "test"; Type type = s.GetType();
3.使用Type类的静态方法GetTyep() Type type =Type.GetType("System.String");
4.Type类常用方法如下:
GetConstructor(), GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息(ConstructorInfo[] constructorInfos = type.GetConstructors();//获取当前Type定义的所有公共构造函数)
GetEvent(), GetEvents():返回EventInfo类型,用于取得该类的事件的信息(EventInfo[] eventInfos = type.GetEvents();//返回当前Type定义或继承的所有公共事件)
GetField(), GetFields():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息(FieldInfo[] fieldInfos = type.GetFields();//返回当前Type所有公共的字段)
GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的所有成员的信息
GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息(MethodInfo[] methodInfo = type.GetMethods();//返回当前Type的所有公共方法)
GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息(PropertyInfo[] propertyInfos = type.GetProperties();//返回当前Type所有公共属性);
2 反射主要用途(dll-IL-metadata-反射),主要是获取程序集或是DLL/exe的matadate信息并使用它(加载dll,读取module、类、属性、字段、方法、特性)
2.1利用反射机制中的Activator创建对象(IOC原理:Reflection+Factory+config)
工厂示例如下:
1 private static string IDBHelpConfig = ConfigurationManager.AppSettings["IDBHelperConfig"]; 2 private static string DllName = IDBHelpConfig.Split(',')[0]; 3 private static string TypeName = IDBHelpConfig.Split(',')[1]; 4 public static IDBHelper CreateInstance() 5 { 6 Assembly assembly = Assembly.Load(DllName);//加载dll//Assembly.Load("DB.Oracle") 7 Type type = assembly.GetType(TypeName);//获取指定类的type信息GetType("DB.Oracle.MyOracleHelper") 8 object oDBHelper = Activator.CreateInstance(type);//创建对象 9 IDBHelper iDBHelper = (IDBHelper)oDBHelper;//类型转换 10 return iDBHelper; 11 }
Assembly assembly = Assembly.Load("DB.SqlServer");
Type type = assembly.GetType("DB.SqlServer.Singleton");
Singleton singleton1 = (Singleton)Activator.CreateInstance(type, true);//反射创建对象调用私用的构造函数
object iDBHelper = Activator.CreateInstance(type, new object[] { "123" });//反射创建对象调用有参数构造函数
2.2利用反射机制获取类中的方法并调用方法(MVC路由原理url地址类名+方法名:Reflection+Method)典型的MVC路由原理通过找类中的方法找到对应的控制控制器和action
Assembly assembly = Assembly.Load("DB.SqlServer");//加载dll
Type type = assembly.GetType("DB.SqlServer.MySqlServer");//获取获取指定类的type信息
MethodInfo methodInfo = type.GetMethod("show");//反射获取方法
methodInfo.Invoke(DBHelper, null);//反射调用无惨方法
MethodInfo methodInfo1 = type.GetMethod("show1");//反射获取方法
methodInfo1.Invoke(DBHelper, new object[] {123 });//反射调用有参数方法
MethodInfo methodInfo4 = type.GetMethod("show2");//反射获取方法
methodInfo4.Invoke(null,null);//反射调用静态无参方法
MethodInfo methodInfo6 = type.GetMethod("show4", BindingFlags.Instance |BindingFlags.NonPublic);//反射获取私有方法
methodInfo6.Invoke(DBHelper, new object[] {123 });//反射调用有参数方法
MethodInfo methodInfo5 = type.GetMethod("Query", new Type[] { typeof(int) });//反射获取重载有参数方法
methodInfo5.Invoke(DBHelper, new object[] {123 });//反射调用重载有参数方法
反射查找泛型类和泛型方法
Assembly assembly = Assembly.Load("DB.SqlServer");
Type typeG = assembly.GetType("DB.SqlServer.GenericTest`1");//反射获取泛型类的类型
Type NewTye = typeG.MakeGenericType(new Type[] { typeof(string) });//指定泛型类的类型
object CreateG = Activator.CreateInstance(NewTye);
MethodInfo methodInfo = NewTye.GetMethod("show");
MethodInfo newmethod=methodInfo.MakeGenericMethod(new Type[] { typeof(int), typeof(string) });//指定泛型类方法参数
newmethod.Invoke(CreateG, new object[] {123,"name" });//调用泛型方法
2.3利用反射机制获取类中的属性字段并使用或设置值(ORM原理:Reflection+Property/Field)
//取得ID字段
FieldInfo fi =
t.GetField("ID");
//给ID字段赋值
fi.SetValue(obj, "k001");
//取得MyName属性
PropertyInfo pi1 =
t.GetProperty("MyName");
//给MyName属性赋值
pi1.SetValue(obj,
"grayworm");
以下实例是需要两个类中的字段属性名字完全相同
1 People people = new People(); 2 people.Id = 123; 3 people.Name = "张三"; 4 people.Description = "张四的哥哥"; 5 Type otype = typeof(People); 6 Type DTOtype = typeof(PeopleDTO); 7 object dtoPeople = Activator.CreateInstance(DTOtype); 8 foreach (var dto in DTOtype.GetProperties()) 9 { 10 object value = otype.GetProperty(dto.Name).GetValue(people);//获取otype中dto.Name属性的值; 11 dto.SetValue(dtoPeople, value);//给dtoPeople该实例中dto属性设置值; 12 dto.SetValue(dtoPeople, otype.GetProperty(dto.Name).GetValue(people));//两者结合 13 } 14 foreach (var dto in DTOtype.GetFields()) 15 { 16 object value = otype.GetField(dto.Name).GetValue(people);//获取otype中dto.Name字段的值; 17 dto.SetValue(dtoPeople, value);//给dtoPeople该实例中dto字段设置值; 18 dto.SetValue(dtoPeople, otype.GetField(dto.Name).GetValue(people));//两者结合 19 }
总结 C#中反射机制用的相当频繁一些大型框架的原理都是基于反射 ,很需要深入了解原理,目前主流的框架MVC ORM IOC等都是利用反射原理实现的