MEF学习系列(1) MEF是什么

前言:

      一种新技术,一个新框架的出现并不是偶然的,它们都是为了解决一定的实际问题。如今IT各种技术、框架的更新很迅速,一步留神就感觉自己out了,当然,技术没有优劣好坏之分,能更好的解决实际问题我们就使用它。MEF也是一样,它能解决很多的现实问题,当然它也有它的局限性。

现实问题:

      在开发大型应用程序,特别是客户端程序,我们会把各个独立的模块/功能包装成一个个小的组件/插件,程序运行时按需加载。这样,我们就要求程序具有很好的扩展能力,包括但不限于以下列出的几个方面:

1. 按需加载组件/插件,动态可拆卸(可动态发现、重用和组合)。

2. 能够在已投产的产品中灵活的加入新功能。

3. 能够支持第三方扩展。

如何解决问题:

  发现问题了便要想办法去解决这些问题。通常为了解决扩展问题,我们都会在框架中设置一些扩展点(或者接口),用于组件(扩展者)的扩展。程序运行时按需(或者按配置)将这些扩展点和扩展者加载并关联。

目前能够满足需求的框架有很多,如:Castle,Unity等,他们都有各自的优缺点,如castle通过在配置文件中显式注册可用组件来实现的,配置文件的劣势在于配置出错后需要很长的时间来解决问题。MSDN的描述如下:

由于应用程序缺乏自己发现组件的能力,因此仍必须明确告知应用程序哪些组件可用并应加载。 这通常是通过在一个配置文件中显式注册可用组件来实现的。 这意味着,确保组件正确无误成为了一个日常维护问题,尤其是在执行更新操作的是最终用户而非开发人员的情况下。

MEF是什么:

      MEF全称是 Managed Extensibility Framework(托管可扩展框架)。单从名字我们不难发现:MEF是专门致力于解决扩展性问题的框架,MSDN中对MEF的说明:

Managed Extensibility Framework 或 MEF 是一个用于创建可扩展的轻型应用程序的库。 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置。 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项。 通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。

为什么选择MEF:

  MEF不是第一种解决扩展问题的框架,但我们之所以使用它还是在于MEF的一些独有的特点,MSDN杂志有一篇文章特别说明了为什么微软还要开发一套可扩展框架,

文章地址:http://msdn.microsoft.com/zh-cn/magazine/ee291628.aspx

针对开发MEF的描述如下:

无论如何,MEF 不是此问题的第一种解决方案。人们提出过许多解决方案 — 跨越平台边界的尝试数不胜数,涉及的工作包括 EJB、CORBA、Eclipse 的 OSGI 实现以及 Java 端的 Spring 等等。在 Microsoft 的平台上,.NET Framework 自身内部包含组件模型和 System.Addin。同时存在若干种开源解决方案,包括 SharpDevelop 的 SODA 体系结构和“控制反转”容器(如 Castle Windsor、Structure Map 以及模式和实践的 Unity)。 既然目前已有这些方法,为何还要引入新事物?这是因为我们意识到,我们当前的所有解决方案对于常规第三方可扩展性都不理想。这些解决方案要么规模过大,不适合常规用途,要么需要主机或扩展开发人员一方完成过多工作。MEF 在最大程度上秉承了所有这些解决方案的优点,尝试解决刚才所提及的令人头痛的问题。

通过上面两端MSDN的说明,我个人对为什么选择MEF总结如下:

1. 它解决了扩展性的问题(这是第一位,不然就没必要接好MEF了)。

2. 它是轻量级的,使用时只需要引用dll类库。

3. 扩展性不是通过配置文件实现,而是使用特性化编程模型。

4. 该框架是开源的,可在codeplex上下载源代码。

5. 它是微软开发的。

“MEF 是 .NET Framework 4 的组成部分,可用在任何使用 .NET Framework 的地方。 可以在客户端应用程序中使用 MEF(无论应用程序使用的是 Windows 窗体、WPF,还是任何其他技术),也可以在使用 ASP.NET 的服务器应用程序中使用 MEF”      ——MSDN

 

MEF的工作原理:

  MEF不同于显示注册可用组件的做法,在MEF中组件被视为部件。这些部件主要有“导入”Import部件和“导出”Export部件,此外MEF提供了一个组合容器ComposeContainer,容器会发现指定Catalog的导入导出部件,并按Contract协定、Metadata元数据等对导入和导出部件进行组合。

通过MEF,应用程序可以通过部件的元数据里发现并检查部件,而不用实例化部件,或者甚至不用加载部件的程序集。因此,没有必要仔细指定应何时以及如何加载扩展。使用MEF编写的可扩展应用程序会声明一个可由扩展组件填充的导入,而且还可能会声明导出,以便向扩展公开应用程序服务。每个扩展组件都会声明一个导出,而且还可能会声明导入。通过这种方式,扩展组件本身是自动扩展的。

 

上述文字已经把MEF中涉及的相关概念指出了,下面具体说明一下:

Export(导出):Export也就是我们常说的组件或者模块或者服务或者插件,它是部件向容器中的其他部件提供的一个值、功能或服务等。

Import(导入):Import,即扩展点,是组件,服务,插件等接入系统的窗口,是部件向要通过导出满足的容器提出的要求,MEF支持若干导入类型,其中包括动态导入、延迟导入、必备导入和可选导入。

Contract(协定):是Export和Import的一种约定,一种协议,只有Contract相匹配的Import和Export部件才能组装成功。

Catalog(目录):为了发现可用于组合容器的部件,组合容器将使用“Catalog”。目录是一个对象,通过发现可用部件,MEF提供了用于从提供的类型、程序集或磁盘路径获取Catalog。

Compose(组合):在MEF中,容器将导入于导出匹配的这一过程我们称之为组合,部件由MEF组合,MEF将部件实例化,然后使导出与导入程序相匹配。

 

DEMO讲解 简单的计算器中使用MEF:

Program.cs:

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

namespace SimpleCalculator3
{

    public interface ICalculator
    {
        String Calculate(String input);
    }

    public interface IOperation
    {
        int Operate(int left, int right);
    }

    public interface IOperationData
    {
        Char Symbol { get; }
    }

    [Export(typeof(IOperation))]
    [ExportMetadata("Symbol", '+')]
    class Add : IOperation
    {
        public int Operate(int left, int right)
        {
            return left + right;
        }
    }

    [Export(typeof(IOperation))]
    [ExportMetadata("Symbol", '-')]
    class Subtract : IOperation
    {

        public int Operate(int left, int right)
        {
            return left - right;
        }

    }



    [Export(typeof(ICalculator))]
    class MySimpleCalculator : ICalculator
    {
        [ImportMany]
        IEnumerable<Lazy<IOperation, IOperationData>> operations;

        public String Calculate(String input)
        {
            int left;
            int right;
            Char operation;
            int fn = FindFirstNonDigit(input); //finds the operator
            if (fn < 0) return "Could not parse command.";

            try
            {
                //separate out the operands
                left = int.Parse(input.Substring(0, fn));
                right = int.Parse(input.Substring(fn + 1));
            }
            catch
            {
                return "Could not parse command.";
            }

            operation = input[fn];

            foreach (Lazy<IOperation, IOperationData> i in operations)
            {
                if (i.Metadata.Symbol.Equals(operation)) return i.Value.Operate(left, right).ToString();
            }
            return "Operation Not Found!";
        }

        private int FindFirstNonDigit(String s)
        {

            for (int i = 0; i < s.Length; i++)
            {
                if (!(Char.IsDigit(s[i]))) return i;
            }
            return -1;
        }


    }


    class Program
    {
        private CompositionContainer _container;

        [Import(typeof(ICalculator))]
        public ICalculator calculator;


        private Program()
        {
            //An aggregate catalog that combines multiple catalogs
            var catalog = new AggregateCatalog();
            //Adds all the parts found in the same assembly as the Program class
            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
            catalog.Catalogs.Add(new DirectoryCatalog(@"E:\开发知识\5. MEF\SimpleCalculator\CS\SimpleCalculator3\Extensions"));


            //Create the CompositionContainer with the parts in the catalog
            _container = new CompositionContainer(catalog);

            //Fill the imports of this object
            try
            {
                this._container.ComposeParts(this);
            }
            catch (CompositionException compositionException)
            {
                Console.WriteLine(compositionException.ToString());
            }
        }


        static void Main(string[] args)
        {
            Program p = new Program(); //Composition is performed in the constructor
            String s;
            Console.WriteLine("Enter Command:");
            while (true)
            {
                s = Console.ReadLine();
                Console.WriteLine(p.calculator.Calculate(s));
            }
            

        }
    }
}


Class1.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;

namespace ExtendedOperations {

    [Export(typeof(SimpleCalculator3.IOperation))]
    [ExportMetadata("Symbol", '%')]
    public class Mod : SimpleCalculator3.IOperation
    {
        public int Operate(int left, int right)
        {
            return left % right;
        }
    }

}


 源代码下载:  http://download.csdn.net/detail/eric_k1m/5987753

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值