组合部件通过[ExportAttribute]声明exports。在MEF中,有这么几种成员可声明exports的方式:组合部件(类)、字段、属性和方法。我们来看下ExportAttribute类的声明:

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=true, Inherited=false)]
public class ExportAttribute : Attribute
{

}

果然,支持这四种成员,另外,在同一个目标上可应用多次该特性但是它不支持继承,如果想继承则需使用ExportAttribute的派生类InheritedExportAttribute来实现。

组合部件导出

组合部件导出被用在当需要导出它自己的时候。在前面的例子中,我们使用的都是这种方式。

    [Export(typeof(IMessageSender))]
    class EmailSender : IMessageSender
    {
        public void Send(string msg)
        {
            Console.WriteLine("Email Sent:"+msg);
        }
    }

这里,我们需要将EmailSender部件自身导出,其实就是类级别的导出。

属性导出

组合部件也可以导出属性。属性导出有这么几个优点:

  • 它允许导出像核心的CLR类型这样的密封类,或者是其它第三方类
  • 它允许将导出创建方式和导出解耦。例如,导出运行时为你创建的已经存在的HttpContext部件
  • 它允许在相同的组合部件中有一些相关的exports,例如一个DefaultSendersRegistry组合部件默认有一系列senders属性导出
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.Composition.Hosting;

namespace ExportsDeclaring
{
    class Program
    {
        [Import]
        public UsesTimeout UsesTimeout { get; set; }
        static void Main(string[] args)
        {
            Program p = new Program();
            p.Compose();
            Console.WriteLine(p.UsesTimeout.Timeout);
            Console.ReadKey();
        }
        void Compose()
        {
            var container = new CompositionContainer();
            container.ComposeParts(this, new UsesTimeout(),new Configuration());
        }
    }
    public class Configuration
    {
        [Export("Timeout")]
        public int Timeout
        {
            get { return int.Parse(ConfigurationManager.AppSettings["Timeout"]); }
        }
    }
    [Export]
    public class UsesTimeout
    {
        [Import("Timeout")]
        public int Timeout { get; set; }
    }
}

在上面的代码之前,需要先在配置文件中配置key为Timeout的AppSetting,例如:<add key="Timeout" value="5000"/>。

输出为:

方法导出

方法导出是用在一个部件要将它的方法导出的地方。通过在导出契约中指定委托的方式来导出方法。方法导出有下面的几点好处:

  • 它允许对于要导出的方法进行细粒度的控制。例如,一个规则引擎可能倒入一系列可插拔的方法导出部件。
  • 它屏蔽了调用者对于类型的了解。
  • 它可以由代码生成器生成,你不需要处理其它的导出部件。

注意:由于框架的限制,方法导出最多不能超过四个参数。

在下面的例子中,MessageSender类将它的Send方法导出为一个Action<string>委托,这个Processor导入了这个相同的委托。

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExportsDeclaring
{
    class Example
    {
        [Import]
        public Processor Processor { get; set; }
        static void Main()
        {
            Example e = new Example();
            e.Compose();
            e.Processor.Send();
            Console.ReadKey();
        }
        void Compose()
        {
            var container = new CompositionContainer();
            container.ComposeParts(this, new Processor(), new MessageSender());
        }
    }
    public class MessageSender
    {
        [Export(typeof(Action<string>))]
        public void Send(string msg)
        {
            Console.WriteLine(msg);
        }
    }
    [Export]
    public class Processor
    {
        [Import(typeof(Action<string>))]
        public Action<string> MessageSender { get; set; }

        public void Send()
        {
            MessageSender("Processed");
        }
    }
}

输出为:

你也可以使用一个简单的字符串契约来导入导出。但是,当进行方法导出时,你必须得提供一个类型或者字符串七月名称,而不能留空。

导出继承

MEF支持在一个基类或者接口中定义的导出将自动地被它的实现类继承的能力。这对于与那些想要利用MEF来发现而不是要求修改已有的客户代码的传统框架来说是很理想的。为了提供这种能力需要使用[System.ComponentModel.Composition.InheritedExportAttribute]。例如下面的ILogger接口有一个[InheritedExport],Logger实现了该接口,因此自动地导出了ILogger。

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExportsDeclaring
{
    class Example1
    {
        [Import]
        public ILogger Logger { get; set; }
        static void Main()
        {
            Example1 e = new Example1();
            e.Compose();
            e.Logger.Log("Logging");
            Console.ReadKey();
        }
        void Compose()
        {
            var container = new CompositionContainer();
            container.ComposeParts(this, new Logger());
        }
    }
    [InheritedExport]
    public interface ILogger
    {
        void Log(string msg);
    }
    public class Logger : ILogger
    {
        public void Log(string msg)
        {
            Console.WriteLine(msg);
        }
    }

}

发现非公有的组合部件

MEF支持公有和非公有部件的发现。你不需要做任何事情来启用该行为。请注意:在并不完全受信任的环境中(包括sliverlight),非公有的组合将不被支持。

MEF初体验之三:Exports声明的更多相关文章

  1. MEF初体验之五:Lazy Exports

    在一个部件组合中,导入将触发一个部件或者多个部件的实例化,这些部件暴露了所需原请求部件的必要的导入.对于一些应用程序来说,延迟实例化-防止图结构下的递归组合-可能对于将创建一个长久复杂的开销很大而不必 ...

  2. MEF初体验之四:Imports声明

    组合部件使用[System.ComponentModel.Composition.ImportAttribute]特性声明导入.与导出类似,也有几种成员支持,即为字段.属性和构造器参数.同样,我们也来 ...

  3. MEF初体验之二:定义组合部件和契约

    组合部件 在MEF中,一个组合部件就是一个组合单元,组合部件"出口"其它组合部件需要的服务并且从其它部件"进口"需要的服务.在MEF编程模型中,为了声明组合部件 ...

  4. MEF初体验之七:Using Catalogs

    MEF特性化编程模型的价值主张之一是通过catalogs动态发现部件的能力.Catalogs允许应用程序很容易地消费那些通过[Export]已经自我注册的exports. Assembly Catal ...

  5. MEF初体验之一:在应用程序宿主MEF

    在MEF出现以前,其实微软已经发布了一个类似的框架,叫MAF(Managed Add-in Framework),它旨在使应用程序孤立和更好的管理扩展,而MEF更关心的是可发现性.扩展性和轻便性,后者 ...

  6. MEF初体验之十二:Composition Batch

    一个MEF容器实例是不可变的.如果catalog支持改变(像观察一个目录的改变)或是如果你的代码在运行时添加或移除部件,改变都可能发生.以前,你不得不作出改变并在组合容器上调用它的组合方法.在Prev ...

  7. MEF初体验之十一:查询组合容器

    查询组合容器 组合容器暴露了几个get exports的重载方法和导出对象和对象集合.你需要注意下面的行为: 当请求单个对象实例时,如果未发现导出,一个异常将被抛出 当请求单个对象实例时,如果发现超过 ...

  8. MEF初体验之十:部件重组

    一些应用程序被设计成在运行时可以动态改变.例如,一个新的扩展被下载,或者因为其它的多种多样的原因其它的扩展变得不可用.MEF处理这些多样的场景是依赖我们称作重组的功能来实现的,它可已在最初的组合后改变 ...

  9. MEF初体验之九:部件生命周期

    理解MEF容器中部件的生命周期及其含义是非常重要的.鉴于MEF重点在开放端应用程序,这将变得尤其重要的,一旦app ships和第三方扩展开始运行,作为应用程序的开发者将很好地控制这一系列的部件.生命 ...

随机推荐

  1. 【原】十张javascript思维导图

    下面附上十张javascript思维导图,如果把里面的内容全部掌握,那就是高手了.思维导图提供给我们一个整体的知识体系,也可以说是一种工具,废话不多说,上图: 1.javascript数据类型 2.j ...

  2. 全国大学列表文件(较新)+ nodejs导入mongodb数据库

    直接上代码 'use strict' var fs=require('fs'), mongodb=require('mongodb').MongoClient, assert=require('ass ...

  3. maven使用

    Maven是一个项目管理和构建自动化工具.但是对于我们程序员来说,我们最关心的是它的项目构建功能,它定义了项目开发的几个标准步骤:编译,发布,单元测试及部署以帮助项目开发 最简单的时候场景是,在pom ...

  4. Linux第十一次学习笔记

    异常控制流 异常控制流(ECF)发生在计算机系统的各个层次 在硬件层,硬件检测到的事件会触发控制突然转移到异常处理程序. 在操作系统层,内核通过上下文转换将控制从一个用户进程转移到另一个用户进程. 在 ...

  5. poj1012.Joseph(数学推论)

    Joseph Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 493  Solved: 311 Description The Joseph's prob ...

  6. MySQL下载安装、配置与使用(win7x64)

    用过MySQL之后,不论容量的话,发现比其他两个(sql server .oracle)好用的多,一下子就喜欢上了.下面给那些还不知道怎么弄的童鞋们写下具体的方法步骤. 工具/原料 电脑 win7 6 ...

  7. Jexus &amp; Mono 迁移

     具体案例: 问:  这个是现在微信公共平台的进三月请求数合计 如果迁移到 Mono & Jexus 需要注意那些?  因为微信需要的是5秒响应,服务号存在时段高峰值,在峰值上,一台服务器能否 ...

  8. ajax中的post方法中回调函数不执行的问题

    前一段时间接触了JQuery Ajax中的.post()方法和.get()方法,感觉到ajax的简洁和强大,当用到.post()方法时,去W3上查找相关的使用方法,感觉十分简单,用法很明了,然后,直接 ...

  9. centos install shutter (How to enable Nux Dextop repository on CentOS or RHEL)

    http://ask.xmodulo.com/enable-nux-dextop-repository-centos-rhel.html Question: I would like to insta ...

  10. Android中attr自定义属性详解

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:wen=http ...