C#在MEF框架中手动导入依赖模块

对于简单的场景来讲,在MEF中导入依赖模块非常简单,只要用ImportAttribute标记依赖的成员,MEF模块会自动找到并创建该模块。但有的时候我们依赖的模块是上下文相关的,此时MEF框架的自动组装满足不了我们的需求了,这里以我之前的文章的一个Log插件为例:

    class HostModule
    {
        [Import]
        ILogger logger = null;

        public string Name { get; private set; }

        public HostModule(string name)
        {
            this.Name = name;
            Compose();

            logger.LogMessage("hello world");
        }

        void Compose()
        {
            var catalog = new AssemblyCatalog(this.GetType().Assembly);
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
        }
    }

    interface ILogger
    {
        void LogMessage(string msg);
    }

    [Export(typeof(ILogger))]
    class ConsoleLogger : ILogger
    {
        public void LogMessage(string msg)
        {
            Console.WriteLine(DateTime.Now + ": " + msg);
        }
    }

现在我想要在Log信息中加入模块名称作为前缀,改成如下形式:

    [Export(typeof(ILogger))]
    class ConsoleLogger : ILogger
    {
        public string ModuleName { get; private set; }

        public void LogMessage(string msg)
        {
            Console.WriteLine(">> " + ModuleName + " | " + DateTime.Now + ": " + msg);
        }
    }

由于MEF框架不知道Logger.ModuleName和HostModule.Name的关系,无法直接通过ImportAttribute标记ModuleName属性搞定。那么,我们该如何传入这ModuleName呢?

通过构造函数导入:

这最直接想到的就是一种方式了,主要修改如下:

  • 在插件模块中创建构造函数,参数为需要导入的依赖模块,并且用ImportingConstructorAttribute标记构造函数。
  • 在构造函数中庸ImportAttribute标记参数
  • 在组装函数中用ComposeExportedValue函数传入参数

示例代码如下:

    class HostModule
    {
        [Import]
        ILogger logger = null;

        public string Name { get; private set; }

        public HostModule(string name)
        {
            this.Name = name;
            Compose();

            logger.LogMessage("hello world");
        }

        void Compose()
        {
            var catalog = new AssemblyCatalog(this.GetType().Assembly);
            var container = new CompositionContainer(catalog);
            container.ComposeExportedValue("ModuleName", this.Name);
            container.ComposeParts(this);
        }
    }

    interface ILogger
    {
        void LogMessage(string msg);
    }

    [Export(typeof(ILogger))]
    class ConsoleLogger : ILogger
    {
        public string ModuleName { get; private set; }

        [ImportingConstructor]
        public ConsoleLogger([Import("ModuleName")] string moduleName)
        {
            this.ModuleName = moduleName;
        }

        public void LogMessage(string msg)
        {
            Console.WriteLine(">> " + ModuleName + " | " + DateTime.Now + ": " + msg);
        }
    }

这种方式一个比较大的缺点就是麻烦,上面的例子还好,如果要导入的参数比较多就显得有点麻烦了。并且后续要新增一个依赖的模块的话则要同时修改好几处处地方,不够集中,容易改漏,并且也不容易排查错误。

在成员中导入

在成员中导入的方式如下:

  • 在Host中用Export标记导出参数
  • 在插件模块中用Import标记导入参数

修改后的代码如下,我把修改的地方标记了一下:

    class HostModule
    {
        [Import]
        ILogger logger = null;

        [Export("ModuleName")]
        public string Name { get; private set; }

        public HostModule(string name)
        {
            this.Name = name;
            Compose();

            logger.LogMessage("hello world");
        }

        void Compose()
        {
            var catalog = new AssemblyCatalog(this.GetType().Assembly);
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
        }
    }

    interface ILogger
    {
        void LogMessage(string msg);
    }

    [Export(typeof(ILogger))]
    class ConsoleLogger : ILogger
    {
        [Import("ModuleName")]
        public string ModuleName { get; private set; }

        public void LogMessage(string msg)
        {
            Console.WriteLine(">> " + ModuleName + " | " + DateTime.Now + ": " + msg);
        }
    }

这种方式改动更少更直观,扩展性也更强,要好用得多了。

进一步解除限制

前面这种方式非常方便,但有一个限制:功能模块是由MEF框架在组装的时候创建的。但是,有的时候,功能模块无法由MEF框架创建(例如在WPF程序中的UI对象,或者一些比较复杂的上下文相关对象),但是,这个时候我们如何手动导入依赖的外部模块呢?MEF框架本身也是提供了比较完善的解决方案的:在执行ComposeParts函数组装的时候将两个对象一并传入一起组装即可。

    class HostModule
    {
        ILogger logger = new ConsoleLogger();

        [Export("ModuleName")]
        public string Name { get; private set; }

        public HostModule(string name)
        {
            this.Name = name;
            Compose();

            logger.LogMessage("hello world");
        }

        void Compose()
        {
            var container = new CompositionContainer();
            container.ComposeParts(this, logger);
        }
    }

    interface ILogger
    {
        void LogMessage(string msg);
    }

    class ConsoleLogger : ILogger
    {
        [Import("ModuleName")]
        public string ModuleName { get; private set; }

        public void LogMessage(string msg)
        {
            Console.WriteLine(">> " + ModuleName + " | " + DateTime.Now + ": " + msg);
        }
    }

小结:虽然前面介绍的这三种方式看起来有不小差别,但归根结底只是不同的组装形式而已,只要掌握了MEF的组装原理,就可以非常自由的组装我们所需要的模块,实现松耦合、简单化、模块化的程序。

到此这篇关于C#在MEF框架中手动导入依赖模块的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • c# RPC框架的使用简介

    写在前面: RPC,听过很有段时间了,但是一直都不太清楚是干嘛的,今天我们来捋一捋. 解释: [Remote Procedure Call Protocol]远程过程调用(就是说,A程序要调用一个b方法,然而这个b方法的实现在B程序内部,B程序还可能和A不在一个电脑上面,怎么调用?http可以调用/rpc也可以,让他像调用本地方法一样调用) 使用初探: 用了一下市面上的,rpc框架,步骤如下: 1.写一个基本的代码,告诉有哪些方法. 2.然后服务端集成, 3.客户端集成, 4.OK调用生效了.

  • 基于MEF打造的插件系统的实现详解

    以实例说话,一起体验MEF带来的可扩展性吧,Let's Rock!!! 1:新建控制台程序SimpleCalculator 在这里要实现的程序时SimpleCalculator,顾名思义:简单的计算器. 所以我们需要定义一个用来计算的接口: public interface ICalculator { String Calculate(String input); } Program 的代码如下: class Program {     private CompositionContainer

  • c# 常用框架汇总

    Json.NET http://json.codeplex.com/ Json.Net 是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单.通过Linq To JSON可以快速的读写Json,通过JsonSerializer可以序列化你的.Net对象.让你轻松实现.Net中所有类型(对象,基本数据类型 等)和Json的转换. Math.NET http://www.mathdotnet.com/ Math.NET的目标是为提供一款自身包含清晰框

  • C# 通过反射初探ORM框架的实现原理(详解)

    背景: 以前学的Java进行开发,多用到Mybatis,Hiberante等ORM框架,最近需要上手一个C#的项目,由于不是特别难,也不想再去学习C#的ORM框架,所以就想着用反射简单的实现一下ORM框架的内容,简单的增删改查,没有用到多表之间的联系. 反射: Java和C#中的反射大体相同,主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义.我的理解就是可以程序运行时动态的获取对象的属性和方法,并且可以进行与之相

  • C#净化版WebApi框架的实现

    前言 我们都知道WebApi是依赖于Asp.Net MVC的 ,所以,想创建WebApi,就需要先创建一个Asp.Net MVC项目. 但用Visual Studio创建的MVC项目通常会带很多功能,而这些功能,很多是我们并不想用的,或者我们想用其他开源控件代替它. 而这样杂乱的起始项目,对于我们这种有精神洁癖的开发者而言,简直是折磨. 所以,让我们编写一个简洁版本的WebApi来净化世界吧. 净化版WebApi预览 首先,我们先看下净化版WebApi的结构. 如上图所示,代码结构很简单,除开配

  • C# CM框架实现多页面管理的实例代码

    概述 之前我分享过一个wpf的项目实践,主页面左侧是个listbox,每次选择改变后呈现对应的页面,界面图如下 要实现这样一个功能,我之前是采用传统方式实现的,本节我采用CM框架下的Conductor<T>去实现,这样代码量可以大幅度压缩,核心代码就一行. 传统方式 后台代码:①定义集合并添加数据: public IViewModel ActiveWindowView { get; set; } public ObservableCollection<string> ListBox

  • C#对Xamarin框架进行数据绑定

    关于数据绑定 Xamarin 单向.双向绑定 Xaml绑定 C#代码绑定 在此之前,几段 伪代码 帮助像我一样菜的同学入门... 假如说,有两个控件,一个是滑动条(Slider),一个是显示文本的标签(Label). Slider slider = new Slider() { Maximum = 1, Value = 10 }; Label label = new Label(); label.Text = slider.Value.ToString(); 滑动条(Slider)滑动的最小单位

  • C#在MEF框架中手动导入依赖模块

    对于简单的场景来讲,在MEF中导入依赖模块非常简单,只要用ImportAttribute标记依赖的成员,MEF模块会自动找到并创建该模块.但有的时候我们依赖的模块是上下文相关的,此时MEF框架的自动组装满足不了我们的需求了,这里以我之前的文章的一个Log插件为例: class HostModule { [Import] ILogger logger = null; public string Name { get; private set; } public HostModule(string

  • C#在MEF框架中实现延迟加载部件

    在MEF的宿主中,当我们通过Import声明导入的对象时,组装(Compose)的时候会创建该对象.例如: interface ILogger { void Log(string message); } [Export(typeof(ILogger))] class ConsoleLogger : ILogger { public void Log(string message) { Console.WriteLine("logger 1" + message); } } class

  • 关于maven使用过程中无法导入依赖的一些总结

    目录 maven使用过程中无法导入依赖的一些总结 maven不自动导入依赖问题 解决办法 maven使用过程中无法导入依赖的一些总结 作为一名java开发的新手,在学习中难免遇见各种问题,在此总结一下. 在使用maven过程中总是碰见某些依赖导不进去的问题,本人使用的是idea2017.maven3.2版本,通过网上搜索和自己的经验归纳为一下几点: 1.settings.xml文件中远程仓库地址的设置 在maven仓库的配置文件中,一般设置远程仓库地址为阿里云的私服,国外的网站也可以就是比较慢,

  • YII2框架中使用RBAC对模块,控制器,方法的权限控制及规则的使用示例

    本文实例讲述了YII2框架中使用RBAC对模块,控制器,方法的权限控制及规则的使用.分享给大家供大家参考,具体如下: 在使用YII2中自带的RBAC时,需要先配置config/web.php: return [ // ... 'components' => [ 'authManager' => [ 'class' => 'yii\rbac\DbManager', ], // ... ], ]; 如果你需要运行yii migrate来创建表,那么config/console.php也需要同

  • 解决springcloud中Feign导入依赖为unknow的情况

    目录 Feign导入依赖为unknow的情况 Feign注解导入失败的处理 Feign导入依赖为unknow的情况 网上很多人在使用的feign时在pom.xml中的依赖为: <!-- SpringCloud 整合 Feign --> <dependency>     <groupId>org.springframework.cloud</groupId>     <artifactId>spring-cloud-starter-feign<

  • 深入解析Java的Spring框架中bean的依赖注入

    每一个基于java的应用程序都有一个共同工作来展示给用户看到的内容作为工作的应用几个对象.当编写一个复杂的Java应用程序,应用程序类应该尽可能独立其他Java类来增加重复使用这些类,并独立于其他类别的测试它们,而这样做单元测试的可能性.依赖注入(或有时称为布线)有助于粘合这些类在一起,同时保持他们的独立. 考虑有其中有一个文本编辑器组件的应用程序,要提供拼写检查.标准的代码将看起来像这样: public class TextEditor { private SpellChecker spell

  • laravel框架中你所用到的依赖注入详解

    前言 用Laravel开发前前后后有2个月左右了,之前一直写Java,就像找到Java和PHP之前的共同点,用Java的某些原理去理解PHP会发现还是有很多共通之处的.Java的依赖注入已经是一个很常见的概念了,Spring框架主要就是解决了这一点,在PHP的laravel框架中,也出现了依赖注入的方式. 依赖注入就控制反转的一种是实现方式,面向对象的特征的重要体现,那么依赖注入中什么是依赖呢,这点用Java开发的人很多都能理解.笼统的说依赖就是一种联系,变量和实现的联系.有关于依赖注入的理解之

  • 深入浅出讲解Spring框架中依赖注入与控制反转及应用

    目录 一. 概念: 1. 使用前: 2. 使用后: 二. 理解控制反转(Ioc): 三. IoC的应用方法 一. 概念: 依赖注入(Dependency Injection,DI)与控制反转(IoC)的含义相同,只不过是从两个角度描述的同一个概念.对于一个Spring初学者来说,这两种称呼都很难理解,我们通过简单的语言来描述这两个概念. 使用对比: 1. 使用前: 当某个Java对象(调用者)需要调用另一个Java对象(被调用者,就是被依赖对象)时,在传统模式下,调用者通常会采用"new被调用者

  • Spring框架中IoC容器与DI依赖注入教程

    目录 一.Spring 是什么 1.1 什么是容器 1.2 什么是 IoC 二.理解 IoC 2.1 传统程序开发的问题 2.2 分析 2.3 控制反转式程序开发 2.4 对比总结规律 2.5 理解 Spring IoC 三.DI 概念说明 四.总结 一.Spring 是什么 我们通常所说的 Spring 指的是 Spring Framework (Spring 框架),它是⼀个开源框架,有着活跃而庞大的社区,这就是它之所以能长久不衰的原因.Spring ⽀持⼴泛的应⽤场景,它可以让 Java

  • 详解ABP框架中的日志管理和设置管理的基本配置

    日志管理 Server side(服务器端) ASP.NET Boilerplate使用Castle Windsor's logging facility日志记录工具,并且可以使用不同的日志类库,比如:Log4Net, NLog, Serilog... 等等.对于所有的日志类库,Castle提供了一个通用的接口来实现,我们可以很方便的处理各种特殊的日志库,而且当业务需要的时候,很容易替换日志组件. 译者注释:Castle是什么:Castle是针对.NET平台的一个开源项目,从数据访问框架ORM到

随机推荐