zoukankan      html  css  js  c++  java
  • Managed Extensibility Framework(MEF) 自动发现式扩展框架

       Managed Extensibility Framework (后称MEF) 是.net 4.0中新增的一个功能特性. 是一个可以自动扩展的轻型框架.以下是MSDN的原版翻译.

    假设您是一个必须提供扩展性支持的大型应用程序的架构师。 您的应用程序必须包含大量可能需要的较小组件,并负责创建和运行这些组件。
    解决这一问题的最简单的方法是:将这些组件作为源代码包括在您的应用程序中,然后通过代码直接调用它们。 这种做法存在很多明显的缺陷。 最重要的是,您无法在不修改源代码的情况下添加新组件,这一限制在 Web 应用程序(举例来说)中也许能够接受,但在客户端应用程序中行不通。 同样存在问题的还有,您可能没有对组件的源代码的访问权,因为这些组件可能是由第三方开发的,而出于相同的原因,您也不允许第三方访问您的代码。
    一种稍微复杂的方法是:提供扩展点或接口,以允许应用程序与其组件相分离。 依据此模型,您可能会提供一个组件能够实现的接口,并提供一个 API 以使该接口能够与您的应用程序进行交互。 这一方法可解决需要源代码访问权的问题,但仍具有自己的难点。
    由于应用程序缺乏自己发现组件的能力,因此仍必须明确告知应用程序哪些组件可用并应加载。 这通常是通过在一个配置文件中显式注册可用组件来实现的。 这意味着,确保组件正确无误成为了一个日常维护问题,尤其是在执行更新操作的是最终用户而非开发人员的情况下。
    此外,各组件之间无法进行通信,除非是通过应用程序自身的严格定义的通道。 如果应用程序架构师未预计到需要某项通信,则通常是无法进行相应的通信的。
    最后,组件开发人员不得不硬依赖于包含他们实现的接口的程序集。 这样就很难在多个应用程序中使用同一个组件,另外,在为组件创建测试框架时也会造成问题。

    在没有MEF的情况下,通常是用反射来完成组件注册使用的.而反射有很多不便之处.需要应用程序知晓命名空间,程序程序集地址,如果是注册一个新组件,通常需要开发人员或专来的维护人员在配置文件中添加新配置.更糟的情况是可能需要修改代码.

    MEF可以通过自动发现机制来管理更新的程序集,无需专业人员参与. 可以轻松完成软件的自动更新升级

    以下代码演示MEF的使用,需要引用System.ComponentModel.Composition.dllSystem.Data.DataSetExtensions.dll

    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; }
        }
    
        //每个运算的元数据是表示对应运算的符号,如 +、-、* 等。 
        //若要使加法运算可用,请将下面的类添加到模块或 SimpleCalculator 命名空间中
    
        //ExportAttribute 特性的功能与以前相同。 ExportMetadataAttribute 特性将元数据以名称/值对的形式附加到相应导出。 
        //尽管 Add 类可实现 IOperation,但并未显式定义实现 IOperationData 的类。 
        //相反,MEF 基于所提供元数据的名称使用属性隐式创建了一个类。 (这是访问 MEF 中的元数据的方法之一。) 
    
        //MEF 中的组合是递归的。 您显式组合 Program 对象,该对象会导入一个证明是 MySimpleCalculator 类型的 ICalculator。 
        //接下来,MySimpleCalculator 将导入 IOperation 对象的集合,
        //而该导入将在创建 MySimpleCalculator 时与 Program 的导入同时进行填充。 
        //如果 Add 类声明了进一步的导入,还必须填充接下来的导入,以此类推。 
        //任何未填充的导入将导致组合错误。 (不过,可以将导入声明为可选导入或为其分配默认值。) 
        [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
        {
            //为了使 SimpleCalculator 能够扩展,它需要导入一组操作。 一般的 ImportAttribute 特性由一个且只由一个 ExportAttribute 填充。 
            //如果有多个导出可用,则组合引擎将生成错误。 
            //若要创建一个可由任意数量的导出填充的导入,可以使用 ImportManyAttribute 特性。 
            [ImportMany]
            //Lazy(Of T, TMetadata) 是 MEF 提供的用于保存对导出的间接引用的类型。 
            //在此,除了导出的对象本身以外,您还将获取导出元数据或描述导出的对象的信息。
            //每个 Lazy(Of T, TMetadata) 都包含一个 IOperation 对象(表示一个实际运算)和一个 IOperationData 对象(表示运算的元数据)。 
            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 循环中,将对 operations 集合的每个成员进行检查。 
                //这些对象的类型是 Lazy(Of T, TMetadata),可分别使用 Metadata 属性和 Value 属性来访问其元数据值和导出的对象。 
                //在此例中,如果发现 IOperationData 对象的 Symbol 属性是一个匹配项,则计算器将调用 IOperation 对象的 Operate 方法并返回结果。
                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()
            {
                //为了发现可用于组合容器的部件,组合容器将使用“目录”。 
                //目录就是一个对象,通过它可从某些源发现可用部件。 
                //MEF 提供了用于从提供的类型、程序集或目录发现部件的目录。
                //应用程序开发人员可以轻松地创建用于从其他源(如 Web 服务)发现部件的新目录。
    
    
                //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:\\Temp"));
    
    
                //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));
                }
                
    
            }
        }
    }


    扩展SimpleCalculator

    新建一个输出类型为类库的项目,添加以下代码

    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;
            }
        }
    
    }

    编译完成后将生成的dll文件copy到E://Temp目录下,运行第一个项目,可以测试扩展的%运算

    曾经年少多少事 而今皆付谈笑中!

  • 相关阅读:
    POJ 1811 Prime Test 素性测试 分解素因子
    sysbench的安装与使用
    电脑中已有VS2005和VS2010安装.NET3.5失败的解决方案
    I.MX6 show battery states in commandLine
    RPi 2B Raspbian system install
    I.MX6 bq27441 driver porting
    I.MX6 隐藏电池图标
    I.MX6 Power off register hacking
    I.MX6 Goodix GT9xx touchscreen driver porting
    busybox filesystem httpd php-5.5.31 sqlite3 webserver
  • 原文地址:https://www.cnblogs.com/xuf22/p/2350754.html
Copyright © 2011-2022 走看看