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

一个软件, 销售给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. Linux打包免安装的Qt程序(编写导出依赖包的脚本copylib.sh,程序启动脚本MyApp.sh)

    本文介绍如何打包Qt程序,使其在没有安装Qt的系统可以运行. 默认前提:另外一个系统和本系统是同一个系统版本. 1,编写导出依赖包的脚本copylib.sh #!/bin/bash LibDir=$P ...

  2. 21.MFC进制转换工具

    相关代码:链接:https://pan.baidu.com/s/1pKVVUZL 密码:e3vf #include <stdlib.h> #include <stdio.h> ...

  3. VC眼中的众筹平台:将改变VC募集基金方式,成为下一个纳斯达克市场

    “一个好的投资平台可能会成为像纳斯达克一样的市场”,这是投资人给予众筹平台的未来憧憬. ”从长远的角度来说,众筹平台可能会改变VC募集基金的方式“,戈壁投资合伙人蒋涛说,“从二级市场看,不论是企业的I ...

  4. 分享一个vue中的vue-Resource用法

    //引入 <script src="//cdn.bootcss.com/vue-resource/1.2.1/vue-resource.js" type="text ...

  5. stylus中文版参考文档之综述

    http://www.zhangxinxu.com/jq/stylus/

  6. Alternating Sum

    http://codeforces.com/problemset/problem/963/A 不考虑正负的话,每两项之间之间公比为b/a,考虑正负,则把k段作为循环节,循环节育循环节之间公比为(b/a ...

  7. javaScript 原型与原型链学习笔记

    javaScript中,原型是常用到一种方式,它能降低储存占用,写出更高效的代码 原型常用到的则是prototype属性 JavaScript prototype 属性 定义和用法 prototype ...

  8. Springboot集成mybatis通用Mapper与分页插件PageHelper

    插件介绍 通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及 Example 相关的单表操作.通用 Mapper 是为了解决 MyBatis 使用 ...

  9. ArcGIS Engine中删除要素的几种方法总结

    转自原文 ArcGIS Engine中删除要素的几种方法总结 /// <summary> /// 通过IFeature.Delete方法删除要素 /// </summary> ...

  10. javaWeb自己定义可排序过滤器注解,解决Servlet3.0下@WebFilter注解无法排序问题

    com.lwl.anno 凝视类型 @WebFilterSort 须要用的jar包 http://download.csdn.net/detail/u013202238/9431110 用该注解注冊的 ...