现在的位置: 首页 > 综合 > 正文

MEF 打造的插件系统

2013年07月03日 ⁄ 综合 ⁄ 共 4022字 ⁄ 字号 评论关闭

以实例说话,一起体验MEF带来的可扩展性吧,Let’s Rock!!!

 

1:新建控制台程序SimpleCalculator

image

在这里要实现的程序时SimpleCalculator,顾名思义:简单的计算器。

所以我们需要定义一个用来计算的接口:

public interface ICalculator

{

    String Calculate(String input);

}

 

Program 的代码如下:

class Program
{
    private CompositionContainer _container;

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

    public Program()
    {
        //var catalog = new AggregateCatalog();
        //catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

        var catalog = new AssemblyCatalog(typeof(Program).Assembly);
        _container = new CompositionContainer(catalog);

        try
        {
            this._container.ComposeParts(this);
        }
        catch (CompositionException compositionException)
        {
            Console.WriteLine(compositionException.ToString());
        }
    }

    static void Main(string[] args)
    {
        Program p = new Program();
        string s;
        Console.WriteLine("Enter Command:");

        while (true)
        {
            s = Console.ReadLine();
            Console.WriteLine(p.calculator.Calculate(s));
        }
    }
}

MEF所要解决的是寻找插件的功能,传统的实现插件的方式主要是使用接口,即声明一个接口,然后使用配置文件来配置接口使用哪个实现类。

 

微软知道有这种需求,于是提供了MEF来实现插件的功能。

 

Composite 原理

1:声明一个 CompositionContainer 对象,这个对象里面包含一堆Catalog.

2:这堆Catalog如果是AssemblyCatalog,则在Assembly中查找,如果是DirectoryCatalog,

Directory 中查找,如果即想要在Assembly中查找,又需要在Directory中查找,

则采用AggregateCatalog

3:然后在这堆Catalog中查找与Import 特性相对应的Export标记所标记的实现类,调用实现类的构造函数进行

Composite(组合)

知道原理后,你也可以自己实现自己的CompositionContainer 类了,

 

要使用MEF 需要为SimpleCalculator添加 System.ComponentModel.Composition.dll 的引用,

然后导入命名空间:

using System.ComponentModel.Composition;

using System.ComponentModel.Composition.Hosting;

接下来看下Program 的构造函数所做的事情:

 

声明一个AssemblyCatalog,指向Program所在的Assembly. 然后把它添加到

CompositionContainer中,调用CompositionContainer ComposeParts 扩展方法,来Compose(this) Parts

 

注:ComposeParts 是扩展方法,需要using System.ComponentModel.Composition;

 

OK,如何Compose,在哪个Assembly中查找实现类来进行Compose已经完成了。

目前的问题是:哪些类需要Compose??

 

为了回答这个问题,微软提供了ImportExport特性: 

Import:哪个对象需要Compose。也就是需要被实现类给填充,所以Import标记的是对象,一般该对象是接口,因为如果是具体类的话,那还需要Import吗?

Export:哪个类可以被用来Compose,也就是说这个类是不是可以用来填充的实现类,所以Export标记的是类,而不是具体的某个对象。

 

所以在这里calculator 使用Import 特性来标记:

[Import(typeof(ICalculator))]

private ICalculator calculator;

 

接下来MEF 的组合引擎在ComposeParts(this)的时候,就会在catalog 代表的AssemblyCatalog中查找Export特性所修饰的实现类了,找到实现类后进行Compose

 

如果找不到Export特性修饰的类的话,结果如下:

image

OK,接下来添加一个实现类,并使用Export特性来进行修饰:

[Export(typeof(ICalculator))]

 public class MySimpleCalculator : ICalculator

 {

     public string Calculate(string input)

     {

         return "MySimpleCalculator 处理了" + input;

     }

 }

 

运行结果如下:

image

当然ImportExport还提供了其他的构造函数,所以你还可以将上面的ImportExport修改为:

[Import("calculator1", typeof(ICalculator))]

[Export("calculator1", typeof(ICalculator))]

 

之所以提供ContractNamecalculator1 是因为你可能有多个ICalculator对象需要填充。

 

修改Program的代码如下:

class Program

{

    private CompositionContainer _container;

 

    [Import("calculator1", typeof(ICalculator))]

    private ICalculator calculator1;

 

    [Import("calculator2", typeof(ICalculator))]

    private ICalculator calculator2;

 

    public Program()

    {

        //var catalog = new AggregateCatalog();

        //catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

 

        var catalog = new AssemblyCatalog(typeof(Program).Assembly);

        _container = new CompositionContainer(catalog);

 

        try

        {

            this._container.ComposeParts(this);

        }

        catch(CompositionException compositionException)

        {

            Console.WriteLine(compositionException.ToString());

        }

    }

 

    static void Main(string[] args)

    {

        Program p = new Program();

        string s;

        Console.WriteLine("Enter Command:");

 

        while (true)

        {

            s = Console.ReadLine();

            Console.WriteLine(p.calculator1.Calculate(s));

            Console.WriteLine(p.calculator2.Calculate(s));

        }

    }

}

 

修改Export修饰的类为:

[Export("calculator1", typeof(ICalculator))]

public class MySimpleCalculator1 : ICalculator

{

    public string Calculate(string input)

    {

        return "第一个Calculator 处理了" + input;

    }

}

 

[Export("calculator2", typeof(ICalculator))]

public class MySimpleCalculator2 : ICalculator

{

    public string Calculate(string input)

    {

        return "第二个Calculator 处理了" + input;

    }

}

抱歉!评论已关闭.