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

一个软件, 销售给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利用反射和自定义特性加载功能模块(插件式开发)的更多相关文章

  1. 利用反射跟自定义注解拼接实体对象的查询SQL

    前言 项目中虽然有ORM映射框架来帮我们拼写SQL,简化开发过程,降低开发难度.但难免会出现需要自己拼写SQL的情况,这里分享一个利用反射跟自定义注解拼接实体对象的查询SQL的方法. 代码 自定义注解 ...

  2. 【译】12. Java反射——类的动态加载和重新加载

    原文地址:http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html 博主最近比较忙,争取每周翻译 ...

  3. Django 修改视图文件(views.py)并加载Django模块 + 利用render_to_response()简化加载模块 +locals()

    修改视图代码,让它使用 Django 模板加载功能而不是对模板路径硬编码.返回 current_datetime 视图,进行如下修改: from django.template.loader impo ...

  4. Flex 4 自定义预加载器

    本示例的目的是在Flash Professional里创建自定义预加载器SWC,并扩展SparkDownloadProgressBar类在Flex 4应用程序中使用.    预加载器显示加载进度百分比 ...

  5. 【SpringBoot 基础系列】实现一个自定义配置加载器(应用篇)

    [SpringBoot 基础系列]实现一个自定义配置加载器(应用篇) Spring 中提供了@Value注解,用来绑定配置,可以实现从配置文件中,读取对应的配置并赋值给成员变量:某些时候,我们的配置可 ...

  6. PHP自动加载功能原理解析

    前言 这篇文章是对PHP自动加载功能的一个总结,内容涉及PHP的自动加载功能.PHP的命名空间.PHP的PSR0与PSR4标准等内容. 一.PHP自动加载功能 PHP自动加载功能的由来 在PHP开发过 ...

  7. 也来学学插件式开发续-利用MEF

    前面一个博客:也来学学插件式开发中很多朋友留言说可以用MEF来实现.于是我就试着用MEF实现了一下. 步骤和上一篇差不多,只是加载插件的方式有所不同.这只是一个自己的示例程序,肯定有很多不足之处,欢迎 ...

  8. Angular - 预加载 Angular 模块

    Angular - 预加载延迟模块 在使用路由延迟加载中,我们介绍了如何使用模块来拆分应用,在访问到这个模块的时候, Angular 加载这个模块.但这需要一点时间.在用户第一次点击的时候,会有一点延 ...

  9. RecyclerViewLoadMoreDemo【封装上拉加载功能的RecyclerView,搭配SwipeRefreshLayout实现下拉刷新】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 封装含有上拉加载功能的RecyclerView,然后搭配SwipeRefreshLayout实现下拉刷新.上拉加载功能. 在项目中将 ...

随机推荐

  1. MongoDB 基本使用

    数据库基本操作 连接到mongoDBserver  1 ./bin/mongo 127.0.0.1:12345  查看当前数据库 1 2 3 > show dbs admin  (empty) ...

  2. legend---四、菜鸟教程css3里面有教你炫酷的按钮怎么做

    legend---四.菜鸟教程css3里面有教你炫酷的按钮怎么做 一.总结 一句话总结:想学,总是有很多资料的 1. 自动居中是 margin:100px 0px;么? 自动居中是margin:100 ...

  3. CentOS下安装C/C++开发工具包的最佳方式

    如果你使用的是 Fedora, Red Hat, CentOS, 或者 Scientific Linux 系统,使用下面的命令安装GNU的C/C++开发包和编译器. # yum groupinstal ...

  4. Python3小白初体验

    三层循环嵌套,以后优化 data = { "北京":{ "a":{ ", " }, "b":{ ", &quo ...

  5. shrio 授权

    授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等).在授权中需了解的几个关键对象:主体(Subject).资源(Resource).权限(Permission).角 ...

  6. SQL语句查询数据库所有表和所有字段的详细信息(包括表描述和字段描述)

    select (case then ddd.value else '' end ) as "表名(中文)" --如果表名相同就返回空 , (case then d.name els ...

  7. python 多线程学习小记

    python对于thread的管理中有两个函数:join和setDaemon setDaemon:如果在程序中将子线程设置为守护线程,则该子线程会在主线程结束时自动退出,设置方式为thread.set ...

  8. 如何更新 CentOS 镜像源

    话不多说, 直接上教程. 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.rep ...

  9. Vijos——T1053 Easy sssp

    https://vijos.org/p/1053 描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程 ...

  10. 安装个wampserver 环境 执行php

    php代码执行要有相关环境. 在这里推荐一个环境工具.wampserver :内置了下面工具: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5 ...