涉及内容:

  • 反射与MEF解决方案
  • AppDomain卸载与代理
  • WinForm、WcfRestService示

PRRT1: 反射实现

插件系统的基本目的是实现宿主与组件的隔离,核心是作为接驳约定的接口,宿主使用类型发现及挂载插件,以下是反射实现。

创建类库项目Plugin,添加接口IPlugin:

public interface IPlugin
{
String DoStuff();
}

创建控制台程序HostApp,添加对Plugin项目的引用,Main方法代码:

class Program
{
static void Main(string[] args)
{
IEnumerable<Type> pluginTypes = GetPluginTypes(); foreach (Type pluginType in pluginTypes)
{
IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);
Console.WriteLine(plugin.DoStuff());
}
} private static IEnumerable<Type> GetPluginTypes()
{
String root = AppDomain.CurrentDomain.BaseDirectory;
String[] files = Directory.GetFiles(root, "*.dll", SearchOption.TopDirectoryOnly); foreach (String file in files)
{
Type[] types = Assembly.LoadFrom(file).GetTypes();
foreach (Type type in types)
{
if (type.IsClass && typeof(IPlugin).IsAssignableFrom(type))
{
yield return type;
}
}
}
}
}

创建类库项目MyPlugin1,添加对Plugin项目的引用,添加Plugin1类并实现IPlugin:

public class Plugin1: IPlugin
{
public String DoStuff()
{
return "MyPlugin1 Plugin1.DoStuff";
}
}

修改该项目的属性,在“生成”选项卡中找到输出,将“输出路径”指向HostApp下的bin\Debug文件夹,运行。

宿主使用无参的IPlugin子类完成组件调用。代码逻辑并不复杂但我们还有更优雅的解决方式即MEF框架,这里拿MEF的完成所需功能,组件生命周期等内容并不深入讨论,如有需求请自行MSDN。

PRRT2: MEF实现

MEF框架以Import、Export特性为功能入口,修改MyPlugin项目,引用System.ComponentModel.Composition,为MyPlugin添加Export特性:

[Export(typeof(IPlugin))]
public class Plugin1: IPlugin
{
public String DoStuff()
{
return "MyPlugin1 Plugin1.DoStuff";
}
}

注意Export明确指定导出类型为IPlugin,在Plugin项目中添加类PluginProvider,引用System.ComponentModel.Composition和System.ComponentModel.Composition.Hosting,添加IEnumerable<Lazy<IPlugin>>类型只读属性并标注ImportMany特性:

public class PluginProvider
{
[ImportMany]
public IEnumerable<Lazy<IPlugin>> Plugins { get; private set; } public PluginProvider()
{
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog("."));
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}

抽象基类ComposablePartCatalog表示组件目录,子类DirectoryCatalog使用指定目录进行搜索。PluginProvider使用了当前程序运行目录作为dll路径。同时导入点所在字段或属性可以是IEnumerable<T>、IEnumerable<Lazy<T>>、IEnumerable<Lazy<T, TMetadata>>等,延迟绑定能相对降低内存开销,这里使用了第2种,接着修改Main方法:

class Program
{
static void Main(string[] args)
{
PluginProvider pluginProvider = new PluginProvider();
foreach (Lazy<IPlugin> plugin in pluginProvider.Plugins)
{
Console.WriteLine(plugin.Value.DoStuff());
}
}
}

运行得到同样的结果,代码更加优雅;根据需求,修改PluginProvider的导入逻辑及使用泛型版本,将得到更多的灵活性。代码文件

附求职信息:目前在北京,寻求.Net相关职位,偏向后端,请邮件jusfr.v#gmail.com,替换#为@,沟通后奉上简历。

动态加载与插件系统的初步实现(一):反射与MEF解决方案的更多相关文章

  1. 动态加载与插件系统的初步实现(3):WinForm示例

    动态加载与插件系统的初步实现(三):WinForm示例 代码文件在此Download,本文章围绕前文所述默认AppDomain.插件容器AppDomain两个域及IPlugin.PluginProvi ...

  2. 动态加载与插件系统的初步实现(四):解析JSON、扩展Fiddler

    按文章结构,这部分应该给出WCFRest项目示例,我想WinForm示例足够详尽了,况且WCFRest还不需要使用插件AppDomain那一套,于是把最近写的Fiddler扩展搬上来吧. Fiddle ...

  3. 动态加载与插件系统的初步实现(三):WinForm示例

    代码文件在此Download,本文章围绕前文所述默认AppDomain.插件容器AppDomain两个域及IPlugin.PluginProvider.PluginProxy3个类的使用与变化进行. ...

  4. 动态加载与插件系统的初步实现(二):AppDomain卸载与代理

    前一篇文章简单展示了类型发现和MEF使用,本文初步进入AppDomain相关内容. CLR程序运行时会创建默认程序集容器即AppDomain,默认AppDomain不支持卸载其程序集,但CLR支持创建 ...

  5. C# 实现动态加载DLL插件 及HRESULT:0x80131047处理

    本代码实现DLL的动态加载, 类似PS里的滤镜插件! 1. 建立一个接口项目类库,此处名称为:Test.IPlugin using System; namespace Test.IPlugin { p ...

  6. vue动态加载jQuery插件

    要先npm安装jQuery插件哦 window.$=$; window.jQuery=$; function loadJs(Url,callback){ var Nscript=document.cr ...

  7. Java_Java中动态加载jar文件和class文件

    转自:http://blog.csdn.net/mousebaby808/article/details/31788325 概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下 ...

  8. [转载] Java中动态加载jar文件和class文件

    转载自http://blog.csdn.net/mousebaby808/article/details/31788325 概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下 ...

  9. c#实现动态加载Dll(转)

    c#实现动态加载Dll 分类: .net2009-12-28 13:54 3652人阅读 评论(1) 收藏 举报 dllc#assemblynullexceptionclass 原理如下: 1.利用反 ...

随机推荐

  1. VMware 11 安装苹果系统

    没事研究了一下虚拟机安装苹果系统 1.下载需要的软件- F, c1 X: e- o1 }& V/ o9 J        1.1 VMware 11 下载和安装* P( R; O6 v1 N! ...

  2. mysql8.0 安装

    之前一直使用的是zabbix3.4和mariadb5.5;感觉良好!!!但是...因其他原因需要重新部署 这次规划使用zabbix4.0和mysql8.0结合使用:嗯~~应该不会错吧!!! zabbi ...

  3. django中session的存储位置

    django-session 存放位置 设置session的保存位置,有三种方法: 保存在关系数据库(db) 保存在缓存数据库(cache) 或者 关系+缓存数据库(cache_db) 保存在文件系统 ...

  4. C++项目第五次作业之文件的读取

    前言 乍看题目,用文件读取数据,这不是很简单的事嘛ps:以前写单个.cpp就是用freopen读取数据,然而当开始写的时候就出现了问题(什么叫做实力作死,有一种痛叫too young too simp ...

  5. 一个查询ip地址的mysql数据库--ip2nation

    http://ip2nation.com/ip2nation/Sample_Scripts/Country_Based_Redirect 并且已经集成进了laravel:https://github. ...

  6. 预估高并发下API服务器数量

    我的主要工作就是API的编写,应该关注API的响应时间,以及并发时候的响应.那么如何测试API响应时间,以及预计高并发服务器压力呢? 从访问日志开始查起. 1 首先统计API每日访问总数.举例假设某个 ...

  7. 使用Oracle的instr函数与索引配合提高模糊查询的效率

    使用Oracle的instr函数与索引配合提高模糊查询的效率 一般来说,在Oracle数据库中,我们对tb表的name字段进行模糊查询会采用下面两种方式:1.select * from tb wher ...

  8. BZOJ 1821 Group 部落划分 并查集

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1821 题目大意: 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所 ...

  9. programming-languages学习笔记--第10部分

    programming-languages学习笔记–第10部分 */--> pre.src {background-color: #292b2e; color: #b2b2b2;} pre.sr ...

  10. Sequelize-nodejs-1-getting started

    Sequelize is a promise-based ORM for Node.js v4 and up. It supports the dialects PostgreSQL, MySQL, ...