• 动态加载与插件系统的初步实现(一):反射与MEF解决方案


    涉及内容:

    • 反射与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下的binDebug文件夹,运行。

    宿主使用无参的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,替换#为@,沟通后奉上简历。

  • 相关阅读:
    Google和Baidu的站内搜索代码
    poj 4468Spy(kmp算法)
    eclipse.ini 内存设置
    ExtJS梦想之旅(八)--GridPanel和EditorGridPanel的使用
    USB线插拔检测使用UEventObserver检测uevent事件的分析
    VNC XEN 双鼠标问题 以及 使用 virt-manager 工具创建的 Xen 虚拟机配置文件不在 /etc/xen/ 目录中了
    输入法分类总结与优缺点
    Codeforces Round #443 (Div. 1) A. Short Program
    论文泛读:Click Fraud Detection: Adversarial Pattern Recognition over 5 Years at Microsoft
    keras用vgg16做图像分类
  • 原文地址:https://www.cnblogs.com/Jusfr/p/3149851.html
Copyright © 2020-2023  润新知