• 基于MEF打造的插件系统的实现详解


    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??

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

    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

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

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

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

    之所以提供ContractName为calculator1 是因为你可能有多个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;

    }

    }

    运行结果如下:

    image

    因为Import和Export是一一对应的,在现实世界中,存在着大量一对多的情况,微软也预料到了这种情况,所以提供了ImportMany 特性。

    在上个例子中的MySimpleCalculator的Calculate方法返回的是一句话,在这个例子中要真正实现计算的功能,例如输入5+3,输出8,输入7*4,输出28。

    为了支持 + - * / 四种Operation.所以在MySimpleCalculator中声明一个operations 的列表。

    [Export(typeof(ICalculator))]

    class MySimpleCalculator : ICalculator

    {

    [ImportMany]

    IEnumerable<Lazy<IOperation, IOperationData>> operations;

    public string Calculate(string input)

    {

    return "calculate 处理了" + input;

    }

    }

    之所以在MySimpleCalculator 中声明operations ,是因为是计算器支持多种运算。因为operations 需要多个operation 来Compose(填充),所以使用ImportMany特性来修饰,和Import特性一样,ImportMany特性一般也是修饰接口。

    Ioperation 和IOperationData的定义如下:

    public interface IOperation

    {

    int Operate(int left, int right);

    }

    public interface IOperationData

    {

    Char Symbol { get; }

    }

    Lazy<IOperation, IOperationData> operations:

    提供对对象及其关联的元数据的延迟间接引用,以供 Managed Extensibility Framework 使用。

    意思是说IOperation 和IOperationData之间的引用需要延迟,为什么需要延迟?,因为IOperation需要根据IOperationData的Symbol符号来延迟创建。

    也就是说,如果IOperationData的Symbol 等于 “+”,那么IOperation对象是AddOperation.如果IOperationData的Symbol等于”-”,那么IOperation对象是SubtractOperation.

    那么如何保证这点呢?

    关键点就在于ExportMetadata attribute 上。

    看下Add Operation 的定义:

    [Export(typeof(IOperation))]

    [ExportMetadata("Symbol", '+')]

    class Add : IOperation

    {

    public int Operate(int left, int right)

    {

    return left + right;

    }

    }

    在这里ExportMetadata特性的Symbol 为+。所以当IOperationData的Symbol为”+” 的时候,匹配的就是Add Operation

    MySimpleCalculator 的完整代码如下:

    [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 = FindFirstNonDigitPosition(input);

    if (fn < 0) return "Could not parse command.";

    try

    {

    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 FindFirstNonDigitPosition(string s)

    {

    for (int i = 0; i < s.Length; i++)

    {

    if (!(Char.IsDigit(s[i]))) return i;

    }

    return -1;

    }

    }

    回头再看看上例的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));

    }

    }

    }

    当this._container.ComposeParts(this); 的时候,MEF组合引擎就开始对标记了Import特性的接口进行Compose,所以在这里是calculator。在哪里找实现类呢?,AssemblyCatalog表明在Program的当前Assembly中查找实现类,所以找到了MySimpleCalculator在构造MySimpleCalculator 的时候,发现了ImportMany特性修饰的operations。于是继续在AssemblyCatalog中找到了Add。

    上面的过程是Compose的过程。

    那么MySimpleCalculator 如何进行Calculate的呢?

    例如5+3

    1:找出第一个非数字的位置,也就是需要找出 +。

    2:声明left,right.并且left 为5,right为3.

    3:根据符号+来构造IOperation对象,接着调用IOperation对象的Operate(left,right)方法。

    foreach (Lazy<IOperation, IOperationData> i in operations)

    {

    if (i.Metadata.Symbol.Equals(operation))

    return i.Value.Operate(left, right).ToString();

    }

    运行结果:

    image

    因为目前定义了Add 的Operation。所以根据符号+ 能够找到Add,但是*我们没有定义,所以Operation Not Found!.

    于是开始定义Multiple:

    [Export(typeof(IOperation))]

    [ExportMetadata("Symbol", '*')]

    class Multiple : IOperation

    {

    public int Operate(int left, int right)

    {

    return left * right;

    }

    }

    再次运行,结果如下:

    image

    当然还可以在当前程序集下面增加- ,/,^,% 等Operation。

    为了让事情更加的有趣,我打算在Debug目录下增加一个目录CalculateExtensions,然后将-,/ ..的Operation放到里面来,让MEF自动发现。

    image

    首先新建类库项目:SimpleCalculatorExtension

    因为需要实现IOperation ,所以需要添加对SimpleCalculator项目的引用。

    因为需要Export特性,所以需要添加对System.ComponentModel.Composition的引用。

    整个项目的结果如下:

    image

    Subtract代码如下:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.ComponentModel.Composition;

    namespace SimpleCalculatorExtension

    {

    [Export(typeof(SimpleCalculator.IOperation))]

    [ExportMetadata("Symbol", '-')]

    class Subtract : SimpleCalculator.IOperation

    {

    public int Operate(int left, int right)

    {

    return left - right;

    }

    }

    }

    生成成功后,将SimpleCalculatorExtension.dll 拷贝到CalculateExtensions目录下:

    现在SimpleCalculator的Debug目录应该是这样。

    image

    并且CalculateExtensions文件夹下面有SimpleCalculatorExtension.dll.

    接下来唯一要修改的是Program的catalog 对象。

    为了让catalog既支持在Program的Assembly中查找,又支持在CalculateExtensions目录下查找。修改代码如下:

    public Program()

    {

    var catalog = new AggregateCatalog();

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

    catalog.Catalogs.Add(new DirectoryCatalog("CalculateExtensions"));

    _container = new CompositionContainer(catalog);

    try

    {

    this._container.ComposeParts(this);

    }

    catch(CompositionException compositionException)

    {

    Console.WriteLine(compositionException.ToString());

    }

    }

    运行结果如下:

    image

    修改SimpleCalculatorExtension 的Subtract方法为:

    namespace SimpleCalculatorExtension

    {

    [Export(typeof(SimpleCalculator.IOperation))]

    [ExportMetadata("Symbol", '-')]

    class Subtract : SimpleCalculator.IOperation

    {

    public int Operate(int left, int right)

    {

    Console.WriteLine("SimpleCalculatorExtension的方法");

    return left - right;

    }

    }

    }

    重新生成SimpleCalculatorExtension.dll 然后拷贝到CalculateExtensions 文件夹下:

    再次运行程序,输出入下:

    image

    文章有点长,而且有点乱,最好自己动手实践下MEF,不过讲的都是MEF的基础,希望对你有所帮助,另外如果你不使用MEF,采用面向接口的编程原则的话,相信你自己也很容易实现自己的“MEF”

    】:

    以实例说话,一起体验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??

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

    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

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

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

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

    之所以提供ContractName为calculator1 是因为你可能有多个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;

    }

    }

    运行结果如下:

    image

    因为Import和Export是一一对应的,在现实世界中,存在着大量一对多的情况,微软也预料到了这种情况,所以提供了ImportMany 特性。

    在上个例子中的MySimpleCalculator的Calculate方法返回的是一句话,在这个例子中要真正实现计算的功能,例如输入5+3,输出8,输入7*4,输出28。

    为了支持 + - * / 四种Operation.所以在MySimpleCalculator中声明一个operations 的列表。

    [Export(typeof(ICalculator))]

    class MySimpleCalculator : ICalculator

    {

    [ImportMany]

    IEnumerable<Lazy<IOperation, IOperationData>> operations;

    public string Calculate(string input)

    {

    return "calculate 处理了" + input;

    }

    }

    之所以在MySimpleCalculator 中声明operations ,是因为是计算器支持多种运算。因为operations 需要多个operation 来Compose(填充),所以使用ImportMany特性来修饰,和Import特性一样,ImportMany特性一般也是修饰接口。

    Ioperation 和IOperationData的定义如下:

    public interface IOperation

    {

    int Operate(int left, int right);

    }

    public interface IOperationData

    {

    Char Symbol { get; }

    }

    Lazy<IOperation, IOperationData> operations:

    提供对对象及其关联的元数据的延迟间接引用,以供 Managed Extensibility Framework 使用。

    意思是说IOperation 和IOperationData之间的引用需要延迟,为什么需要延迟?,因为IOperation需要根据IOperationData的Symbol符号来延迟创建。

    也就是说,如果IOperationData的Symbol 等于 “+”,那么IOperation对象是AddOperation.如果IOperationData的Symbol等于”-”,那么IOperation对象是SubtractOperation.

    那么如何保证这点呢?

    关键点就在于ExportMetadata attribute 上。

    看下Add Operation 的定义:

    [Export(typeof(IOperation))]

    [ExportMetadata("Symbol", '+')]

    class Add : IOperation

    {

    public int Operate(int left, int right)

    {

    return left + right;

    }

    }

    在这里ExportMetadata特性的Symbol 为+。所以当IOperationData的Symbol为”+” 的时候,匹配的就是Add Operation

    MySimpleCalculator 的完整代码如下:

    [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 = FindFirstNonDigitPosition(input);

    if (fn < 0) return "Could not parse command.";

    try

    {

    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 FindFirstNonDigitPosition(string s)

    {

    for (int i = 0; i < s.Length; i++)

    {

    if (!(Char.IsDigit(s[i]))) return i;

    }

    return -1;

    }

    }

    回头再看看上例的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));

    }

    }

    }

    当this._container.ComposeParts(this); 的时候,MEF组合引擎就开始对标记了Import特性的接口进行Compose,所以在这里是calculator。在哪里找实现类呢?,AssemblyCatalog表明在Program的当前Assembly中查找实现类,所以找到了MySimpleCalculator在构造MySimpleCalculator 的时候,发现了ImportMany特性修饰的operations。于是继续在AssemblyCatalog中找到了Add。

    上面的过程是Compose的过程。

    那么MySimpleCalculator 如何进行Calculate的呢?

    例如5+3

    1:找出第一个非数字的位置,也就是需要找出 +。

    2:声明left,right.并且left 为5,right为3.

    3:根据符号+来构造IOperation对象,接着调用IOperation对象的Operate(left,right)方法。

    foreach (Lazy<IOperation, IOperationData> i in operations)

    {

    if (i.Metadata.Symbol.Equals(operation))

    return i.Value.Operate(left, right).ToString();

    }

    运行结果:

    image

    因为目前定义了Add 的Operation。所以根据符号+ 能够找到Add,但是*我们没有定义,所以Operation Not Found!.

    于是开始定义Multiple:

    [Export(typeof(IOperation))]

    [ExportMetadata("Symbol", '*')]

    class Multiple : IOperation

    {

    public int Operate(int left, int right)

    {

    return left * right;

    }

    }

    再次运行,结果如下:

    image

    当然还可以在当前程序集下面增加- ,/,^,% 等Operation。

    为了让事情更加的有趣,我打算在Debug目录下增加一个目录CalculateExtensions,然后将-,/ ..的Operation放到里面来,让MEF自动发现。

    image

    首先新建类库项目:SimpleCalculatorExtension

    因为需要实现IOperation ,所以需要添加对SimpleCalculator项目的引用。

    因为需要Export特性,所以需要添加对System.ComponentModel.Composition的引用。

    整个项目的结果如下:

    image

    Subtract代码如下:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.ComponentModel.Composition;

    namespace SimpleCalculatorExtension

    {

    [Export(typeof(SimpleCalculator.IOperation))]

    [ExportMetadata("Symbol", '-')]

    class Subtract : SimpleCalculator.IOperation

    {

    public int Operate(int left, int right)

    {

    return left - right;

    }

    }

    }

    生成成功后,将SimpleCalculatorExtension.dll 拷贝到CalculateExtensions目录下:

    现在SimpleCalculator的Debug目录应该是这样。

    image

    并且CalculateExtensions文件夹下面有SimpleCalculatorExtension.dll.

    接下来唯一要修改的是Program的catalog 对象。

    为了让catalog既支持在Program的Assembly中查找,又支持在CalculateExtensions目录下查找。修改代码如下:

    public Program()

    {

    var catalog = new AggregateCatalog();

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

    catalog.Catalogs.Add(new DirectoryCatalog("CalculateExtensions"));

    _container = new CompositionContainer(catalog);

    try

    {

    this._container.ComposeParts(this);

    }

    catch(CompositionException compositionException)

    {

    Console.WriteLine(compositionException.ToString());

    }

    }

    运行结果如下:

    image

    修改SimpleCalculatorExtension 的Subtract方法为:

    namespace SimpleCalculatorExtension

    {

    [Export(typeof(SimpleCalculator.IOperation))]

    [ExportMetadata("Symbol", '-')]

    class Subtract : SimpleCalculator.IOperation

    {

    public int Operate(int left, int right)

    {

    Console.WriteLine("SimpleCalculatorExtension的方法");

    return left - right;

    }

    }

    }

    重新生成SimpleCalculatorExtension.dll 然后拷贝到CalculateExtensions 文件夹下:

    再次运行程序,输出入下:

    image

    文章有点长,而且有点乱,最好自己动手实践下MEF,不过讲的

    详细出处参考:http://www.jb51.net/article/36758.htm

  • 相关阅读:
    POJ 2506 Tiling
    POJ 2586 Y2K Accounting Bug
    POJ 2965 The Pilots Brothers' refrigerator (DFS)
    POJ 2499 Binary Tree
    POJ 3006 Dirichlet's Theorem on Arithmetic Progressions (素数)
    beautifulsoup 基本语法 含class属性查找小技巧class_
    xlrd库的使用
    pytest框架 里 fixture 参数化的方法
    ddt数据驱动
    mac电脑 pip安装包后 撞到了系统python里面的解决方法
  • 原文地址:https://www.cnblogs.com/greefsong/p/3126609.html
Copyright © 2020-2023  润新知