zoukankan      html  css  js  c++  java
  • .NET基础拾遗(5)反射2

      本篇是学习反射的一个应用小场景而做的学习笔记,主要是一个小的总结,并对各个步骤的记录,以便将来回顾。

    一、基础框架-敏捷基础版本

      这里假定我们要开发一个记事本,选择Windows Form技术开发,界面如下图所示:

    Main

      该记事本只提供了一个TextBox供输入,以及保存到指定文件。其他功能均没有实现,假定我们先把这个版本做出来,后续功能通过插件形式一步一步完成。

      但是,为了能够使用插件,我们的主项目还得经过一些改造:

      (1)加载时需要从插件目录中获取插件

        public FormMain()
        {
            InitializeComponent();
            // 加载插件
            LoadPlugins();
        }
    
        private void LoadPlugins()
        {
            // 1.加载plugins目录下的所有的dll文件
            string plugins = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "plugins");
            //   1.1 搜索plugins目录下的所有的dll文件 
            string[] dlls = Directory.GetFiles(plugins, "*.dll");
            // 2.循环将每个dll文件都加载起来
            foreach (string dllPath in dlls)
            {
                //  2.1 动态加载当前循环的dll文件
                Assembly assembly = Assembly.LoadFile(dllPath);
                //  2.2 获取当前dll中的所有的public类型
                Type[] types = assembly.GetExportedTypes();
                //  2.3 获取IEditor接口的Type
                Type typeIEditor = typeof(IEditor);
    
                for (int i = 0; i < types.Length; i++)
                {
                    // 2.4 验证当前的类型即实现了IEditor接口并且该类型还可以被实例化
                    if (typeIEditor.IsAssignableFrom(types[i]) && !types[i].IsAbstract)
                    {
                        IEditor editor = (IEditor)Activator.CreateInstance(types[i]);
                        // 2.5 向菜单栏中动态添加一个菜单项
                        ToolStripItem toolItem = toolstripEditMenu.DropDownItems.Add(editor.PluginName);
                        // 2.6 为刚刚增加的菜单项注册一个单击事件
                        toolItem.Click += new EventHandler(toolItem_Click);
                        toolItem.Tag = editor;
                    }
                }
            }
        }

      (2)为插件设置通用的Click事件

        private void toolItem_Click(object sender, EventArgs e)
        {
            ToolStripItem item = sender as ToolStripItem;
            if (item != null)
            {
                if (item.Tag != null)
                {
                    IEditor editor = item.Tag as IEditor;
                    if (editor != null)
                    {
                        // 运行该插件
                        editor.Execute(this.txtContent);
                    }
                }
            }

      这里约定所有插件都实现了IEditor接口,并且所有插件的功能都在Execute方法中被实现。

    二、约定接口-可扩展的基础

    plugin

      不难发现,如果我们直接使用反射调用dll,即使我们找到了dll文件,也没法知道里面的函数叫什么名字,即使可以枚举出来,也没法智能的调用里面的函数,实现我们预期的功能扩展。于是我们犯难了,我们已经写好的程序哪能预料以后会调用哪些dll的哪些函数呢?

      其实这个并不复杂,我们可以利用接口技术实现这样一种功能。所谓接口,就是一份协议,当大家编写dll时都遵守这样一个协议,那么我们写的dll就可以方便的被exe调用。

      对于这个小demo而言,我们设计一个IEditor接口如下:

        public interface IEditor
        {
            string PluginName
            {
                get;
            }
    
            void Execute(TextBox txtbox);
        }

      其中,PluginName是插件的名称,用于菜单显示。Execute方法则接收记事本的TextBox控件,用于实现具体的功能。

    三、实现插件-可升级的功能

      (1)插件1:将文本全部转为大写

      新建一个类库项目,设计一个实现IEditor接口的类:

        public class ChangeFontStyle : IEditor
        {
            public string PluginName
            {
                get
                {
                    return "转为大写";
                }
            }
    
            public void Execute(TextBox txtbox)
            {
                if (!string.IsNullOrEmpty(txtbox.Text))
                {
                    txtbox.Text = txtbox.Text.ToUpper();
                }
                else
                {
                    MessageBox.Show("请先输入文字!");
                }
            }

      (2)插件2:将文本全部变为红色

      新建一个类库项目,设计一个实现IEditor接口的类:

        public class ChangeFontColor : IEditor
        {
            public string PluginName
            {
                get
                {
                    return "改变颜色";
                }
            }
    
            public void Execute(TextBox txtbox)
            {
                if (!string.IsNullOrEmpty(txtbox.Text))
                {
                    txtbox.ForeColor = System.Drawing.Color.Red;
                }
                else
                {
                    MessageBox.Show("请先输入文字!");
                }
            }
        }

    四、拥抱变化-简单的测试

      (1)没有任何插件的记事本程序

        Plugins 插件目录下一个dll也木有:

    NoPlugins

        因此我们的记事本只有最基本的操作: 

    demo1

      (2)加入插件1(转换大写)的记事本程序

        Plugins 插件目录有一个dll:

    oneplugin

        这时加入了转换大写的功能:

    demo2

      (3)加入插件2(改变颜色)的记事本程序

         Plugins 插件目录有两个dll:

    twopluings

         这时加入了改变颜色的功能:

    demo3

      由此可知,利用反射和接口,我们可以自定义插件实现不同的扩展功能,让我们的主软件项目更为强大!

  • 相关阅读:
    刘强东:当下正是行业谷底,可卖了两辆车的二手车电商却估值2亿美金 传统商业的价值和经济规律完全适用于互联网 任何一种互联网商业模式,如果不能够降低行业的交易成本,不能够提升行业交易效率的话,那么最后注定会失败的。
    学习一样新东西行而有效的方法 学习捷径 一项由10个步骤组成的学习方法
    侃侃程序员的个人努力与前途问题 程序员到底怎么了
    你觉得你在创业,但其实你可能只是在做小生意而已 制定正确的计划 创业和经营小企业之间的差异
    外贸圈 贸易经 外贸心路 一位成功外贸人的SOHO心得
    总结创业成功的共性 企业成功的必要条件 --投资教父阎焱:创业成功的九九八十一难
    Navicat 12.x for MySQL最新版安装破解教程(附安装包和注册机,全网独家可用
    Xmanager PowerSuite 6企业版详细安装破解教程,解决评估过期问题(附注册机,全网独家可用),非学校/家庭免费版
    UltraEdit等软件详细安装破解教程,附注册机(全网独家可用)
    SpringBoot2.0微信小程序支付多次回调问题
  • 原文地址:https://www.cnblogs.com/tiantianle/p/5767974.html
Copyright © 2011-2022 走看看