zoukankan      html  css  js  c++  java
  • C# winform利用反射和自定义特性加载功能模块(插件式开发)

    由于在实际的工作中, 碰见这样的一个问题:

    一个软件, 销售给A客户 他需要所有功能,

    但是销售给B客户, 他只需要其中的一部分,

    1.如果我们在实际的开发过程中, 没有把一些功能模块区分开来的话, 那么带来的麻烦, 势必是要修改源代码。

    2.直到有一天,B客户又说需要某些功能,这个时候, 我们又要修改一次源代码, 更新给客户 , 所以想了想, 如果每个功能块都独立开来, 动态去加载功能, 这样就不用改动源代码, 客户需要哪些功能, 注册那些DLL给他们使用。

    ?.实现思路
    1.每个模块都用单独的程序集(DLL)分开  <反射动态加载>

    2.需要指定每个功能模块的命名空间       <特性标记命名空间

    !.实现代码

    1.程序中定义自定义特性, 用于映射程序的的模块信息和功能模块所在的命名空间

     /// <summary>
        /// 模块编号.
        /// </summary>
        public enum ModuleID
        {
            None = 0,
            DataDictionary = 1,
            SystemManage = 2
        }
    
        /// <summary>
        /// 模块名称.
        /// </summary>
        public class ModuleNames
        {
            public const string DataDictionary = "基础数据";
            public const string SystemManage = "系统管理";
        }
    
        /// <summary>
        /// 模块入口自定义特性
        /// </summary>
        public class AssemblyModuleEntry : Attribute
        {
    
            private ModuleID _moduleID;
            private string _moduleName;
            private string _moduleEntryNameSpace;
    
            /// <summary>
            /// 模块编号
            /// </summary>
            public ModuleID ModuleID { get { return _moduleID; } }
    
            /// <summary>
            /// 模块名称
            /// </summary>
            public string ModuleName { get { return _moduleName; } }
    
            /// <summary>
            /// 模块名字空间
            /// </summary>
            public string ModuleEntryNameSpace { get { return _moduleEntryNameSpace; } }
    
            /// <summary>
            /// 构造器
            /// </summary>
            /// <param name="moduleID">模块编号</param>
            /// <param name="moduleName">模块名称</param>
            /// <param name="moduleEntryNameSpace">模块名字空间</param>
            public AssemblyModuleEntry(ModuleID moduleID, string moduleName, string moduleEntryNameSpace)
            {
                _moduleID = moduleID;
                _moduleName = moduleName;
                _moduleEntryNameSpace = moduleEntryNameSpace;
            }
    
        }

    在模块的程序集设置好新建的自定义特性 (如下):

    // 有关程序集的一般信息由以下
    // 控制。更改这些特性值可修改
    // 与程序集关联的信息。
    [assembly: AssemblyModuleEntry(ModuleID.DataDictionary, ModuleNames.DataDictionary, "My.DataDictionary.Form1")]

    1.定义方法读取程序集(DLL)中的第一个特性信息

    /// <summary>
            /// 获取程序集自定义特性。是否用户自定义模块由AssemblyModuleEntry特性确定。
            /// </summary>
            public static AssemblyModuleEntry GetModuleEntry(Assembly asm)
            {
                AssemblyModuleEntry temp = new AssemblyModuleEntry(ModuleID.None, "", "");
                if (asm == null) return temp;
    
                object[] list = asm.GetCustomAttributes(typeof(AssemblyModuleEntry), false);
                if (list.Length > 0)
                    return (AssemblyModuleEntry)list[0];
                else
                    return temp;
            }

    2.保存AssemblyModuleEntry 的特性信息, 解析特性信息利用反射映射功能模块的主窗体

     /// <summary>
            /// 加载模块主方法
            /// </summary>
            /// <param name="moduleinfo">模块信息</param>
            /// <returns></returns>
            public virtual bool LoadModule(ModuleInfo moduleinfo)
            {
                _ModuleFileName = moduleinfo.ModuleFile;
                _ModuleAssembly = moduleinfo.ModuleAssembly;
                string entry = GetModuleEntryNameSpace(_ModuleAssembly);
                if (string.Empty == entry) return false;
    
                Form form = (Form)_ModuleAssembly.CreateInstance(entry);  //根据命名空间加载Form
                _ModuleMainForm = null;
    
                if (form is IModuleBase) _ModuleMainForm = (IModuleBase)form;
    
                return _ModuleMainForm != null;
            }

    3.将功能模块的功能都加载到全局缓存对象中, 创建首页的UI控件, 将缓存对象中的模块加载到首页中。

     

    实际效果图:

    注意: 反射是会带来性能的损耗, 但是经过合理的优化,还是对性能影响不大, 当个这个设计, 主要看每个人使用的取舍。

    核心思想:

    1.定义自定义特性

    2.将功能命名空间存储到自定义特性中(主要用于反射获取到指定的功能界面区)

    3.利用反射去获取目录下的有特性的程序集,加载指定的功能

    4.将反射获取的指定界面转换成缓存对象

    5.将缓存对象转换成首页指定的UI控件上。

    PS: 关于权限的控制思路:

    针对所登陆得用户, 获取当前用户所有的权限, 根据权限加载权限内的程序集。

    ---恢复内容结束---

  • 相关阅读:
    SQL ——索引、视图和事务
    流控制语句
    SQL Server 高级编程之T-SQL 编程函数
    SQL高级编程之waitfor
    数据库主键、外键、唯一等约束
    打代码会遇到的单词
    前端词云图
    docker+mysql集群+读写分离+mycat管理+垂直分库+负载均衡
    lvs+keepalived实现Mycat的负载均衡--高可用
    mycat配置数据库集群
  • 原文地址:https://www.cnblogs.com/zh7791/p/7910901.html
Copyright © 2011-2022 走看看