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 }

以上代码,仅为了掩饰效果,因为本人较懒,因此就不写其他运算符插件; 运行上述代码:

效果如图:

                                                 

以上就是 反射插件技术的小示例:(有错误的地方还待各位博友更正);

其实反射还有很多其他用处,也有待后续学习的发现,相信这个对初学者还是有一定帮助的

 

           

 

posted on 2013-11-21 01:25  三分钟~\乐度  阅读(281)  评论(0编辑  收藏  举报