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实现下拉刷新.上拉加载功能. 在项目中将 ...
随机推荐
- 改动npm包管理器的registry为淘宝镜像(npm.taobao.org)
起因 安装了node.安装了npm之后,官方的源实在是 太慢了! 看了看淘宝的npm镜像, http://npm.taobao.org/ 居然说让我再下载一个cnpm,要不然就每次都得install ...
- jquery基本Dom操作
1 html()获取所有的html内容 2 html(value) 设置html内容,有html自动解析 3 text() 获取文本内容 4 text(value) 设置文本内容,有html自动转义 ...
- drbd脑裂
环境: Primary 节点:node1Secondary 节点:node2 DRBD产生脑裂的原因: (1. 采用HA环境的时候自动切换导致脑裂; (2. 人为操作或配置失误,导 ...
- display 表格模型值
display:inline-table 此元素会作为内联表格来显示(类似 <table>),表格前后没有换行符.display:inline-table 可以使文字和表格在同一行显示 d ...
- cz.msebera.android.httpclient.conn.ConnectTimeoutException: Connect to /192.168.23.1:8080 timed out(Android访问后台一直说链接超时)
明明之前还是可以运行的练习,过段时间却运行不了,一直说访问后台超时, 对于这个问题我整整弄了两天加一个晚上,心酸...,上网找了很多但是都解决不了,我就差没有砸电脑了. 首先 : 第一步:Androi ...
- 循环GridControl所有行
; i < gridView1.RowCount; i++) { DataRowView row = (DataRowView)gridView1.GetRow(i); } gridView1是 ...
- Mysql第八天 分区与分表
分区表 主要提供例如以下的特性,或者适合如此场景: 数据量非常大, 或者仅仅有表中最后的部分有热点数据.其它均为历史数据 分区表数据更easy维护,能够对独立的分区删除等操作 分区表的数据能够分布在不 ...
- PAT-中国大学MOOC-陈越、何钦铭-数据结构基础习题集 00-自測4. Have Fun with Numbers (20) 【二星级】
题目链接:http://www.patest.cn/contests/mooc-ds/00-%E8%87%AA%E6%B5%8B4 题面: 00-自測4. Have Fun with Numbers ...
- .net运行项目的几种形式
1.通过配置IIS 2.通过VS运行项目 3.发布到测试服务器 不同于PHP的发布,直接把相关的类文件传入ftp即可. .net的发布是编译好dll文件,将dll文件传入即可. 比如改了某个文件,就把 ...
- 洛谷P2251 质量检测
题目背景 无 题目描述 为了检测生产流水线上总共N件产品的质量,我们首先给每一件产品打一个分数A表示其品质,然后统计前M件产品中质量最差的产品的分值Q[m] = min{A1, A2, ... Am} ...