c# 高级技术--反射

反射? 难道是物理中光的反射??  NO、NO、NO !!! 这个“反射”和物理一点关系都没有!!

那什么是反射呢? 我个人的理解是:在程序中 动态的添加程序的功能(添加dll文件) 无需在源代码中添加 从而实现为程序的功能“升级”。

说的有些官方了 下面我举几个例子
 我们都玩过游戏 就拿我以前玩的QQ飞车来说 游戏厂商会隔一段时间对游戏进行升级 比如说音乐、赛道等 由于QQ飞车的客户端已经下载到我们
的电脑上了 每次游戏升级的时候不可能让我们重新下载一遍客户端吧 要是这样的话 QQ飞车会被骂死的 那该怎么办呢?
 在游戏升级完毕的时候 有没有注意到 在游戏的安装目录下 多了几个文件夹 文件夹中又多了几个.dll问文件
哈哈 以前没有注意到的可以现在去看一下 没错 这就是传说中的“反射”!!
 晕!! 就多了几个文件 QQ飞车中就能有那么多音乐 和 那么多复杂的赛道?
 没错 下面我来大概说一下反射的原理吧 我个人的理解 比较肤浅 :
 在我们写主程序的时候 就比如说QQ飞车的主程序 里面的功能并不是写死的 而是留有一个类似于对外接口的东西
这样做的目的就是为了以后能为主程序添加更多的功能
 在主程序中 分为以下几个步骤:
  1. 窗体在加载的时候 搜索dll目录下的所有的.dll文件

     2. 获取.dll文件中具有插件功能的类

     3. 通过调用插件中类的方法 来实现程序中的功能扩展

     4. 开发主程序的人必去做一个约定:所有为程序开发插件的人 必须将插件执行的方法命名为固定的一个名字

     5. 主程序的开发人员不管开发者插件的人定义了多少个类 多少个方法 在主程序中 只去调用规定好的那个名字的方法 这就是主程序与插件开发者之间的一个约定

主程序代码:    

 // 窗体在加载的时候

        private void Form1_Load(object sender, EventArgs e)

        {

            // 1. 窗体在加载的时候搜索dll目录下的所有的.dll文件

            // 1.1 获取当前运行的exe的绝对路径

            //Assembly.GetExecutingAssembly().Location;

            // 1.2 获取当前运行的exe文件路径的目录部分

            string exeDirPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            // 1.3 拼接dll文件的绝对路径

            string dllFullPath = Path.Combine(exeDirPath, "dll");

            // 1.4 搜索指定目录下的所有dll文件

            string[] dellPaths = Directory.GetFiles(dllFullPath, "*.dll");

            // 1.5 循环遍历加载所有的dll文件

            for (int i = 0; i < dellPaths.Length; i++)

            {

                // 将每一个dll都加载进来

                Assembly asm = Assembly.LoadFile(dellPaths[i]);

 

                // 获取当前dll(插件)中的public

                Type[] typePublic = asm.GetExportedTypes();

 

                // 获取接口的类型

                Type typeIExecute = typeof(IExecute);

 

                // 循环判断 typePublic 中的每个类是否实现了 IExecute 接口

                // 循环判断改类型是否可以被实例化不是抽象的

                for (int j = 0; j < typePublic.Length; j++)

                {

                    if (typeIExecute.IsAssignableFrom(typePublic[j]) && !typePublic[j].IsAbstract)

                    {

                        // 根据类型的type 创建对象

                        // 由于已经知道 typePublic[j] 是实现了 IExecute 接口的

                        // 所以强转成IExecute接口然后通过接口变量来操作类的成员了

                        IExecute execut = (IExecute)Activator.CreateInstance(typePublic[j]);

 

                        // 给主程序中的菜单栏名称赋值

                        ToolStripItem tsoitem = MymenuStrip.Items.Add(execut.ExeName);

 

                        // 给增加的功能实现单击事件

                        tsoitem.Click += new EventHandler(tsoitem_Click);

 

                        // 将接口对象 execut 放在新增的对象的tag属性中

                        tsoitem.Tag = execut;

                    }

                }

            }

        }

 

        ///<summary>

        ///给增加的功能实现单击事件

        ///</summary>

        ///<param name="sender"></param>

        ///<param name="e"></param>

        void tsoitem_Click(object sender, EventArgs e)

        {

            // 转换成接口的类型

            IExecute execut = (IExecute)((ToolStripItem)sender).Tag;

 

            execut.Execute(textBox1);

        }

 

定义的接口:

public interface IExecute

    {

        ///<summary>

        ///插件的名称用来显示在主程序中

        ///</summary>

 

        string ExeName

        {

            get;

            set;

        }

 

        ///<summary>

        ///插件执行的方法

        ///</summary>

        void Execute(TextBox text);

    }

 
  其实我们程序员每天都在应用反射
  我们在使用.的时候 就是应用了反射 当我们.的时候 会反射当前程序的元数据 将所有的方法,类等信息全部显示出来 方便程序员使用 大大提高了编程效率!
  
 
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值