C# winform利用反射和自定义特性加载功能模块(插件式开发)
由于在实际的工作中, 碰见这样的一个问题:
一个软件, 销售给A客户 他需要所有功能,
但是销售给B客户, 他只需要其中的一部分,
1.如果我们在实际的开发过程中, 没有把一些功能模块区分开来的话, 那么带来的麻烦, 势必是要修改源代码。
2.直到有一天,B客户又说需要某些功能,这个时候, 我们又要修改一次源代码, 更新给客户 , 所以想了想, 如果每个功能块都独立开来, 动态去加载功能, 这样就不用改动源代码, 客户需要哪些功能, 注册那些DLL给他们使用。
?.实现思路
1.每个模块都用单独的程序集(DLL)分开 <反射动态加载>
2.需要指定每个功能模块的命名空间 <特性标记命名空间>
!.实现代码
1.程序中定义自定义特性, 用于映射程序的的模块信息和功能模块所在的命名空间
/// <summary>
/// 模块编号.
/// </summary>
public enum ModuleID
{
None = ,
DataDictionary = ,
SystemManage =
} /// <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 > )
return (AssemblyModuleEntry)list[];
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: 关于权限的控制思路:
针对所登陆得用户, 获取当前用户所有的权限, 根据权限加载权限内的程序集。
---恢复内容结束---
C# winform利用反射和自定义特性加载功能模块(插件式开发)的更多相关文章
- 利用反射跟自定义注解拼接实体对象的查询SQL
前言 项目中虽然有ORM映射框架来帮我们拼写SQL,简化开发过程,降低开发难度.但难免会出现需要自己拼写SQL的情况,这里分享一个利用反射跟自定义注解拼接实体对象的查询SQL的方法. 代码 自定义注解 ...
- 【译】12. Java反射——类的动态加载和重新加载
原文地址:http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html 博主最近比较忙,争取每周翻译 ...
- Django 修改视图文件(views.py)并加载Django模块 + 利用render_to_response()简化加载模块 +locals()
修改视图代码,让它使用 Django 模板加载功能而不是对模板路径硬编码.返回 current_datetime 视图,进行如下修改: from django.template.loader impo ...
- Flex 4 自定义预加载器
本示例的目的是在Flash Professional里创建自定义预加载器SWC,并扩展SparkDownloadProgressBar类在Flex 4应用程序中使用. 预加载器显示加载进度百分比 ...
- 【SpringBoot 基础系列】实现一个自定义配置加载器(应用篇)
[SpringBoot 基础系列]实现一个自定义配置加载器(应用篇) Spring 中提供了@Value注解,用来绑定配置,可以实现从配置文件中,读取对应的配置并赋值给成员变量:某些时候,我们的配置可 ...
- PHP自动加载功能原理解析
前言 这篇文章是对PHP自动加载功能的一个总结,内容涉及PHP的自动加载功能.PHP的命名空间.PHP的PSR0与PSR4标准等内容. 一.PHP自动加载功能 PHP自动加载功能的由来 在PHP开发过 ...
- 也来学学插件式开发续-利用MEF
前面一个博客:也来学学插件式开发中很多朋友留言说可以用MEF来实现.于是我就试着用MEF实现了一下. 步骤和上一篇差不多,只是加载插件的方式有所不同.这只是一个自己的示例程序,肯定有很多不足之处,欢迎 ...
- Angular - 预加载 Angular 模块
Angular - 预加载延迟模块 在使用路由延迟加载中,我们介绍了如何使用模块来拆分应用,在访问到这个模块的时候, Angular 加载这个模块.但这需要一点时间.在用户第一次点击的时候,会有一点延 ...
- RecyclerViewLoadMoreDemo【封装上拉加载功能的RecyclerView,搭配SwipeRefreshLayout实现下拉刷新】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 封装含有上拉加载功能的RecyclerView,然后搭配SwipeRefreshLayout实现下拉刷新.上拉加载功能. 在项目中将 ...
随机推荐
- Linux打包免安装的Qt程序(编写导出依赖包的脚本copylib.sh,程序启动脚本MyApp.sh)
本文介绍如何打包Qt程序,使其在没有安装Qt的系统可以运行. 默认前提:另外一个系统和本系统是同一个系统版本. 1,编写导出依赖包的脚本copylib.sh #!/bin/bash LibDir=$P ...
- 21.MFC进制转换工具
相关代码:链接:https://pan.baidu.com/s/1pKVVUZL 密码:e3vf #include <stdlib.h> #include <stdio.h> ...
- VC眼中的众筹平台:将改变VC募集基金方式,成为下一个纳斯达克市场
“一个好的投资平台可能会成为像纳斯达克一样的市场”,这是投资人给予众筹平台的未来憧憬. ”从长远的角度来说,众筹平台可能会改变VC募集基金的方式“,戈壁投资合伙人蒋涛说,“从二级市场看,不论是企业的I ...
- 分享一个vue中的vue-Resource用法
//引入 <script src="//cdn.bootcss.com/vue-resource/1.2.1/vue-resource.js" type="text ...
- stylus中文版参考文档之综述
http://www.zhangxinxu.com/jq/stylus/
- Alternating Sum
http://codeforces.com/problemset/problem/963/A 不考虑正负的话,每两项之间之间公比为b/a,考虑正负,则把k段作为循环节,循环节育循环节之间公比为(b/a ...
- javaScript 原型与原型链学习笔记
javaScript中,原型是常用到一种方式,它能降低储存占用,写出更高效的代码 原型常用到的则是prototype属性 JavaScript prototype 属性 定义和用法 prototype ...
- Springboot集成mybatis通用Mapper与分页插件PageHelper
插件介绍 通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及 Example 相关的单表操作.通用 Mapper 是为了解决 MyBatis 使用 ...
- ArcGIS Engine中删除要素的几种方法总结
转自原文 ArcGIS Engine中删除要素的几种方法总结 /// <summary> /// 通过IFeature.Delete方法删除要素 /// </summary> ...
- javaWeb自己定义可排序过滤器注解,解决Servlet3.0下@WebFilter注解无法排序问题
com.lwl.anno 凝视类型 @WebFilterSort 须要用的jar包 http://download.csdn.net/detail/u013202238/9431110 用该注解注冊的 ...