• MEF基础概念学习笔记


             MEF,是微软.net框架下的一个框架类库。可以使你的程序低耦合的加载扩展。在开发插件,或者开发一些需要灵活扩展的功能的时候经常用到。例如微软给出的计算器的例子。当你开发计算器的时候,初始功能只提供了加减功能。但后来你要扩展乘法,除法功能。显然,如果去改整个程序就会使问题变得麻烦,并且有不可预知的问题。所以微软提供给我们使用MEF来通过动态加载扩展的方法来给程序增加新功能。另外,mef,也可以用来实现依赖注入,控制反转。

          我们先从最简单的DEMO开始学习mef.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Reflection;
    
    namespace MEFDEMO
    {
        class Program
        {
            [Import]
            public string Message { get; set; }
            static void Main(string[] args)
            {
                Program program = new Program();
                program.Run();
            }
            public void Run()
            {
                var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
                var container = new CompositionContainer(catalog);
                container.ComposeParts(this);
              
                Console.WriteLine(Message);
                Console.ReadKey();
            }
        }
        public class SimpleHello
        {
            [Export]
            public string Message
            {
                get { return "Hello World!"; }
            }
        }
    }

         这是一个最简单的例子。从上面可以看出一个简单的mef实现由下面几个部分组成

         1.   一个程序用来调用的入口      [Import] public string Message { get; set; }

         2.   方法的具体实现                 [Export]  public string Message{get { return "Hello World!"; }}

              方法的具体实现也就是我们可以动态增加的部分。和一般的接口实现相比,通过MEF的实现使其更灵活,更易扩展。可动态添加   

         3.   将上面两个方法组合起来的,建立两者之间的联系。

               var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

               var container = new CompositionContainer(catalog);

               container.ComposeParts(this);

       
              关于如何建立两者之间的联系,在这个例子中我们是通过,获得当前程序集运行的目录,将当前目录放到一个容器中,最后通过ComposeParts(this);方法将容器container中export的方法import到实现了import特性的具体实现。我们现在来了解几个MEF中常用到的类。

              ComposablePart 类:定义用于导入对象和生成已导出对象的可组合部件的抽象基类。也就是说这个类的每一个实例里面都放了里面放了一组ExportDefinitionsImportDefinitions,我们可以把每一个实例称作一个部件。

              ComposablePartCatalog 类:表示收集并返回 ComposablePartDefinition 对象的可组合部件目录的抽象基类。也就是里面存放了一堆部件所在程序集的目录,注意这里不是存放了一堆部件,而是这些部件所在程序集的目录,也就是我们去找所有部件的索引项。

              ExportProvider 类:检索与指定的 ImportDefinition 对象相匹配的导出。这个类的作用很明确,就是用来寻找与 ImportDefinition 对象匹配的ExportDefinition

              CompositionContainer 类:管理部件的组合。也就是用来管理ComposablePart部件的一个容器类。里面放了我们的一组组部件。注意这个类继承自ExportProvider这个类。

    上面几个类是mef中抽象出来的几个类,理清这几个类的关系,我们在应用mef的时候才能高清mef的使用步骤。

    下面这几个类继承自  ExportProvider 类,都能访问到相关的部件,但每一个类的侧重都不同。

    System.ComponentModel.Composition.Hosting.AggregateExportProvider

    检索由 ExportProvider 对象的集合提供的导出。
    System.ComponentModel.Composition.Hosting.CatalogExportProvider

    从目录中检索导出。                       
    System.ComponentModel.Composition.Hosting.ComposablePartExportProvider

    检索来自某个部件的导出。
    System.ComponentModel.Composition.Hosting.CompositionContainer

    侧重于管理部件,上面定义已给出。

    下面这几个类继承自  ComposablePartCatalog 类,都是每个部件的存放目录,但每一个类的侧重都不同。

    System.ComponentModel.Composition.Hosting.AggregateCatalog

    合并 ComposablePartCatalog 对象元素的目录。
    System.ComponentModel.Composition.Hosting.AssemblyCatalog

    在托管代码程序集中发现特性化部件。
    System.ComponentModel.Composition.Hosting.DirectoryCatalog

    发现所指定目录中的程序集的特性化的部分。
    System.ComponentModel.Composition.Hosting.TypeCatalog

    从类型集合发现特性化部件。

    其它一些类:

    CompositionBatch 类:表示一组将添加至一个事务性组合的容器中或从容器中移除的 ComposablePart 对象。

    ExportAttribute 类:指定某个类型、属性、字段或方法提供特定的导出。

    ImportAttribute 类:指定属性、字段或参数值应由 CompositionContainer 提供。

    总之,常用到的类有以上几个,还有一些其它用到的,请直接去参考msdn.

    理解了上述几个类,然后我们去看我们上面的例子中将部件组合的过程。

    var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());

    取到当前程序集运行的目录,这儿当然我们也可以去取别的程序集的目录,比如我们插件所在的扩展目录。可用如下代码去取

              

                System.ComponentModel.Composition.Hosting.AggregateCatalog category = new System.ComponentModel.Composition.Hosting.AggregateCatalog();
    
                foreach (var file in System.IO.Directory.GetFiles(@"C:UserswfmDocumentsVisual Studio 2013ProjectsWPFTestTestReferenceinDebug"))
                {
                    if (file.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase))
                    {
                        try
                        {
                            var assembly = Assembly.LoadFile(file);
                            if (assembly == Assembly.GetCallingAssembly())
                                continue;
                            category.Catalogs.Add(new System.ComponentModel.Composition.Hosting.AssemblyCatalog(assembly));
                        }
                        catch
                        {
                        }
                    }
                }
                Container = new CompositionContainer(category, true);
                this.Container.ComposeParts(this);

        

    var container = new CompositionContainer(catalog);

          这句代码创建了一个容器,创建容器很简单,这要传入一个ComposablePartCatalog类或者其子类就可以,也可以传入ExportProvider类,具体的看该方法的重载。

    container.ComposeParts(this);

          这里ComposeParts是一个扩展方法。调用的时候省略第一个参数。所以这里传入的this,类型:System.Object[]要组合的特性化对象的数组。也就是把这儿的[Import]  public string Message { get; set; } 传过去,然后容器就去寻找和该需要的导入对象匹配的导出对象。

          在这个例子中我们是用的container.ComposeParts(this);来组合的导入导出。但是还有其他方法。例如:
          container.SatisfyImportsOnce(this);
          container.Compose(batch);
          T 实例= Container.GetExportedValue<T>();然后通过实例去调用。

       

    本文地址:http://www.cnblogs.com/santian/p/4355730.html

    博客地址:http://www.cnblogs.com/santian/

    转载请以超链接形式标明文章原始出处。
  • 相关阅读:
    POJ 2750 Potted Flower (单点改动求线段树上最大子序列和)
    [异能程序猿]第四章 偶遇(第四更)
    【web开发学习笔记】Struts-Tags学习笔记1
    UVa 10100
    【算法拾遗】大数相加(不开辟额外空间)
    cocos2d-html5学习笔记(六)--alpha2中cc.Sequence.create中的bug
    大一暑假和大二专业学习的规划
    Android如何获得系统版本
    Struts2——(1)Struts2入门
    设置m_pszAppName值的做法
  • 原文地址:https://www.cnblogs.com/santian/p/4355730.html
Copyright © 2020-2023  润新知