反射主要使用的命名空间:
System.Reflection
System.Type
System.Reflection.Assembly
本质:元数据
反射的本质其实是使用元数据;元数据其实就是程序编译出来的特定数据结构的表;当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等;用过c++的可能会类比一下头文件;
反射的作用就是解析使用这些元数据;上面的几个命名空间就是实现这些解析与使用。
示例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Practice.NET.Reflact { public class Product { public string Name { get; set; } public decimal Price { get; set; } public Product() { } public Product(string name, decimal price) { this.Name = name; this.Price = price; } public void PrintName() { Console.WriteLine(this.Name); } void PrintPrice() { Console.WriteLine(this.Price.ToString()); } public string GetName(string name) { this.Name = name; return this.Name; } public void GetName() { PrintName(); } public void ShowPrice(ref decimal price) { this.Price = price; } } }
using System; using System.Reflection; namespace Practice.NET.Reflact { public class ReflactTest { /// <summary> /// 基本用法 /// </summary> public void Test() { //1、-------------------------程序集------------------------ string path = AppDomain.CurrentDomain.BaseDirectory + "Practice.NET.exe";//; Assembly ass = Assembly.LoadFrom(path); //2、--------------------------类-------------------- //第一种方法,在类的构造函数是无参时使用方便,在有参时就不容易实现 object obj1 = ass.CreateInstance("Practice.NET.Reflact.Product");//实例化Person类,返回值是object,通过命名空间及类名得到 Type myType1 = obj1.GetType(); //得到类的类型 //第二种方法,通过获得类型的构造函数来实例化对象,在构造函数是有参时也容易实现 Type myType2 = ass.GetType("Practice.NET.Reflact.Product");//得到类的类型 ConstructorInfo constructor = myType2.GetConstructor(new Type[0]);//得到myType的构造函数(无参) object instance2 = constructor.Invoke(null);//调用构造函数来实现实例化类现在先通过调用无参构造函数来实例化类,下面看一下通过反射怎么得到类成员: //3、--------------------方法------------------------- MethodInfo method1 = myType2.GetMethod("PrintName");//得到无参公有方法 MethodInfo method2 = myType2.GetMethod("PrintPrice", BindingFlags.Instance | BindingFlags.NonPublic);//得到私有方法 MethodInfo method3 = myType2.GetMethod("GetName", new Type[] { typeof(string) });//得到带参数的公有方法(后面的Type类型可以省略,但如果是重载方法就不能省) MethodInfo method4 = myType2.GetMethod("GetName", new Type[0]); MethodInfo method5 = myType2.GetMethod("ShowPrice");//得到参数是ref的的方法 //4、-----------------------------属性------------------ //得到属性 PropertyInfo[] propertys = myType2.GetProperties(BindingFlags.Instance | BindingFlags.Public); PropertyInfo Name = myType2.GetProperty("Name"); PropertyInfo Price = myType2.GetProperty("Price"); FieldInfo name = myType2.GetField("name", BindingFlags.Instance | BindingFlags.NonPublic);//得到字段(全是私有的) FieldInfo age = myType2.GetField("name", BindingFlags.Instance | BindingFlags.NonPublic); //设置/读取属性 Name.SetValue(instance2, "李四", null);//给Name设值,后面的null是对应的索引器 Price.SetValue(instance2, 23M, null); Name.GetValue(instance2); //5、----------------特性 myParamAttribute-------------- //foreach (var item in propertys) //{ //item.GetCustomAttributes(typeof(myAttribute), true).Length //返回item包含myAttribute特性的数组 //} //6、----------------调用方法------------ method1.Invoke(instance2, null); method2.Invoke(instance2, null); Console.WriteLine(method3.Invoke(instance2, new object[] { "王五" }));//调用有返回值的方法 method4.Invoke(instance2, null); method5.Invoke(instance2, new object[] { 14M });//调用参数是ref的方法 } } }