2013-11-21
一.什么是反射
记得当我初次学程序的是时候就接触了程序集这个概念,当时只对编程的初步了解,也没记个多少,只记得 (程序集里包含很多个模块,而模块又包含了很多类型,而类型又
包含了很多成员),然后前几天才刚学了反射,我的理解就是: 反射就是提供了已经封装好了程序集、模块和类型的对象,让编程人员可以通过发射所提供的对象去访问
程序集里面的允许访问的东西,也就是(public);
如下图所示:
二.为什么要使用反射
当然,刚学反射的时候我也有这个疑问,为什么学习反射呢?以及学了他有什么作用呢?一上百度一搜编程反射,弹出的链接还真不少,于是乎就随意打开一个网页,哪里有
老鸟说到:反射是一个程序员的必备技能,不会反射的早在公司卷铺盖走人了!我一看到这话,惊出一身冷汗(—_—当然这个夸张了点),有句号说:“不听老鸟言,吃亏在
眼前”!既然前辈都把反射说的那么重要,那作为新手还是赶紧学学; 至于反射的作用,例如(我们在是在使用360浏览器,你把链接到一个英文网站,他有自动提示,是否把
当前网页翻译成中文,然后你点击是,你会很神奇的发现,一下子你看不懂的洋鬼子符号,全部都转为天朝官方文字了,这时候你就能感觉到浏览器的强大之处,但是这里其
实只不过是用了反射的插件技术,也就是浏览器会提供一个接口【interface】,接入一个实现接口翻译插件工具,于是乎便扩展了浏览器的功能),在惊叹浏览器的功能强大
之外,作为一个程序员,我们应该理解这两个东东是怎么工作的,具体是怎么实现的!接下来,为你揭秘反射机制的工作原理,以及实例;
如下图所示:
三.如何运用反射
我们都知道,任何能在windows系统运行下的程序都会有一个(*.dll 或者 *.exe 文件),插件也不例外,这时我们的计算机就要去解析里面的文件,再把他转换成计算机能
读懂的语言,但是如何解析呢?接下来我们就用c#语法来说明反射几个比较重要的获取程序集、类型、以及成员的语法:
//首先要引用一个命名空间
using System.Reflection;
//获取程序集对象
Assembly asb=Assembly.LoadFrom("dll文件的存取路径对象");
//获取程序集所有类型对象(注:类型对象就是类的对象,类其实也是一个类型)
Type[] types=asb.GetTypes();
//获取类型的命名空间名
string nameSpace=asb.GetName().name;
//获得类名
string className=types.Name;
//获取单个类型对象
Type type=asb.GetType("命名空间.类名");
//获取程序集共有方法对象
MethodInfo[] mis=type.GetMethods();
//获取程序集方法参数对象
ParameterInfo[] pis=mis.GetParameters();
//获取程序集构造函数对象
ConstructorInfo[] cis=type.GetConstructors();
//获取程序集属性对象
PropertyInfo[] pts=type.GetPropertys();
//获取程序集字段对象
FieldInfo[] fis=type.GetFields();
————以上就是 反射技术 常用的获取各种对象的方法;
接下来通过一个简易计算器来展示反射插件技术的用法:
把界面当作主程序,把运算符当作插件
主程序界面如图:
主程序代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Reflection; using System.IO; using CalculatorInterface; namespace CalculatorProject { public partial class Form1 : Form { //放置计算类对象的集合 private List<ICalculate> CalculateMethod = new List<ICalculate>(); public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { //构建放置计算类的dll文件的路径 //Application.ExecutablePath 当前应用程序的执行程序的文件路径 string path = Application.ExecutablePath; path = path.Substring(0, path.LastIndexOf('\\')); path = path + "\\lib"; //根据路径创建文件夹对象 DirectoryInfo dir = new DirectoryInfo(path); FileInfo[] files = dir.GetFiles("*.dll"); //获取文件夹对象下的文件 //使用反射技术读取所有dll文件中的类 foreach (FileInfo file in files) { Assembly ass = Assembly.LoadFrom(file.FullName); Type[] types = ass.GetTypes(); //取出一个类型 foreach (Type type in types) { //判断该类型是否继承了接口 ICalculate Type it = typeof(ICalculate); if(it.IsAssignableFrom(type)) { //如果是计算类,则创建计算对象,并加入到集合中 CalculateMethod.Add((ICalculate)Activator.CreateInstance(type)); } } } //从计算对象的集合中循环读取其运算符 foreach (ICalculate ic in CalculateMethod) { cboOperator.Items.Add(ic.Operator); } } private void label1_Click(object sender, EventArgs e) { //取出文本框中的数据 int num1 = Convert.ToInt32(txtNum1.Text); int num2 = Convert.ToInt32(txtNum2.Text); int result = 0; //从计算对象的集合中取出选择的计算对象 ICalculate ic = CalculateMethod[cboOperator.SelectedIndex]; result = ic.Calcu(num1, num2);//调用计算方法计算结果 //显示结果 lblResult.Text = result.ToString(); } } }
主程序提供接口代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace CalculatorInterface 7 { 8 public interface ICalculate 9 { 10 //返回运算符的属性 11 string Operator { get; } 12 //声明计算方法 13 int Calcu(int x, int y); 14 } 15 }
接下来是插件部分代码: 也就是(运算符当作插件:),记得要引用主程序提供的接口
加法插件:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 using CalculatorInterface; 7 8 namespace MyCalculator 9 { 10 //采用类的方式封装 具体的计算过程 11 public class AddClass : ICalculate 12 { 13 public string Operator 14 { 15 get { return "+"; } 16 } 17 18 public int Calcu(int x, int y) 19 { 20 return x + y; 21 } 22 } 23 }
减法插件代码:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 using CalculatorInterface; 7 8 namespace MyCalculator 9 { 10 public class SubClass : ICalculate 11 { 12 public string Operator 13 { 14 get { return "-"; } 15 } 16 17 18 public int Calcu(int x, int y) 19 { 20 return x - y; 21 } 22 } 23 }
以上代码,仅为了掩饰效果,因为本人较懒,因此就不写其他运算符插件; 运行上述代码:
效果如图:
以上就是 反射插件技术的小示例:(有错误的地方还待各位博友更正);
其实反射还有很多其他用处,也有待后续学习的发现,相信这个对初学者还是有一定帮助的