反射
在使用反射之前要先了解程序集;
我们写好的程序最终都会被编译成exe或dll。程序集(Assembly)通常表现为一个文件(.exe或.dll文件),
除此之外程序集还包含资源文件,类型元数据(描述在代码中定义的每一类型和成员,二进制形式)、IL代码(这些都被装在exe或dll中)
通过Assembly类可以获取程序集信息
AppDomain.CurrentDomain.GetAssemblies()获取当前程序集加载的外部程序集
Assembly.LoadFile(),动态从文件加载Assembly,不需要在编译的时候引用。
反射无处不在,我们天天在使用。Vs的智能提示,就是通过反射获取到类的属性、方法等。还有反编译工具也是通过反射实现
反射就是动态获取程序集的元数据(提供程序集的类型信息)的功能
Type类实现反射的一个重要的类,通过它我们可以获取类中的所有信息包括方法、属性等。可以动态调用类的属性、方法。 Type是对类的描述
Type类的使用:
•通过类获得Type:Type t = typeof(Person)
•通过对象获得类的Type:Type t = p.GetType()
•调用Assembly的GetExportedTypes方法可以得到Assembly中定义的所有的public类型。
View Code
•调用Assembly的GetTypes()方法可以得到Assembly中定义的所有的类型。
•调用Assembly的GetType(name)方法可以得到Assembly中定义的全名为name的类型信息。
动态创建对象
Activator.CreateInstance(Type t)会动态调用类的无参构造函数创建一个对象,返回值就是创建的对象,如果类没有无参构造函数就会报错。
Type类方法
bool IsAssignableFrom(Type c)判断当前的类型的变量是不是可以接受c类型变量的赋值。
public class Student:Person{} Person p=new Student(); typeof(Person ).IsAssignableFrom((typeof(Student)));//true 因为Student s=new Person ();肯定不成立 所以typeof(Person ).IsAssignableFrom((typeof(Student)))就为false
bool IsInstanceOfType(object o):判断对象o是否是当前类的实例(当前类可以是o的类、父类、接口)
bool IsSubclassOf(Type c):判断当前类是否是类c的子类.
动态调用成员
MemberInfo类 抽象类,有很多子类,下面讲的类都继承自它,获取程序集成员的相关信息(类型、方法、事件、字段和属性)
PropertyInfo 获取属性
•主要成员:CanRead、CanWrite、PropertyType属性类型;SetValue、GetValue:读取值,设置值,第一个参数是实例对象,因为set、get要针对具体实例,最后一个参数null。pInfo.SetValue(p1, 30, null)
Person p = new Person(); Type type = p.GetType(); PropertyInfo[] pis = type.GetProperties(); foreach (PropertyInfo item in pis) { if (item.Name == "Name") { item.SetValue(p, "张三", null); } } Console.WriteLine(p.Name);
MethodInfo 获取方法
•MethodInfo都是和具体对象不相关的,所以需要第一个参数指定要执行的对象。
FieldInfo 获取字段
EventInfo 获取事件
自己写插件:
1.写一个接口,用来提供名称,跟执行方法
IPlugin
public interface IPlugin { string Name { get; } string Execute(string str); }
2.两个实现了接口类:自动关机的,查字典的
ShutDown
class ShutDown:IPlugin { public string Name { get { return "定时关机"; } } string IPlugin.Execute(string second) { Process process = new Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardInput = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; process.Start(); process.StandardInput.WriteLine("shutdown -s -f -t " + second); //process.StandardInput.WriteLine("dir c:"); process.StandardInput.WriteLine("exit"); process.Close(); return null; } }
Dictionary
class Dictionary:IPlugin { public string Name { get { return "字典" ;} } public string Execute(string str) { Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("eat", "吃"); dic.Add("food","食物"); if (dic.ContainsKey(str)) { return dic[str]; } else { return "没有要查的单词"; } } }
3.在windows应用程序的Debug目录下新建一个Plugins文件夹,上面两个应用程序编译好后,把ShutDown.dll,Dictionary.dll放到该文件夹里,还需要添加接口的引用
From
private void Form1_Load(object sender, EventArgs e) { //1.获取程序集路径 string path = AppDomain.CurrentDomain.BaseDirectory; path = Path.Combine(path,"Plugins"); //2.获取dll文件详细名称 string[] strs = Directory.GetFiles(path, "*.dll"); foreach (string item in strs) { //3程序集内容 Assembly ass = Assembly.LoadFile(item); //4找要程序集中定义的所以类型 Type[] types = ass.GetTypes(); foreach (Type type in types) { //5该类型是实现了接口的类 if (typeof(IPlugin).IsAssignableFrom(type) && !type.IsAbstract && type.IsClass) { //object o= Activator.CreateInstance(type); //MethodInfo mi= type.GetMethod(""); //mi.Invoke(o, new object[] { }); IPlugin ip = Activator.CreateInstance(type) as IPlugin; ToolStripItem tsi= tsmi.DropDownItems.Add(ip.Name); tsi.Tag = ip; tsi.Click += new EventHandler(tsi_Click); } } } } void tsi_Click(object sender, EventArgs e) { ToolStripItem tsi = sender as ToolStripItem; if (tsi != null) { IPlugin ip = tsi.Tag as IPlugin; if (!string.IsNullOrEmpty(textBox1.Text)) { string a = ip.Execute(textBox1.Text); MessageBox.Show(a); } else { MessageBox.Show("请输入秒数"); } } }