源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

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

  • 时间:2022-09-03 06:45 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:基于MEF打造的插件系统的实现详解
[b]以实例说话,一起体验MEF带来的可扩展性吧,Let's Rock!!![/b] 1:新建控制台程序SimpleCalculator [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645267909.png][img]http://files.jb51.net/file_images/article/201305/20130513150942110.png[/img] [/url] 在这里要实现的程序时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来实现插件的功能。 [b]Composite [/b][b]原理[/b]: 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。 [b]注:ComposeParts 是扩展方法,需要using System.ComponentModel.Composition; [/b] OK,如何Compose,在哪个Assembly中查找实现类来进行Compose已经完成了。 目前的问题是:[b]哪些类需要[/b][b]Compose??[/b] 为了回答这个问题,微软提供了Import和Export特性:  [b]Import[/b]:哪个对象需要Compose。也就是需要被实现类给填充,所以Import标记的是对象,一般该对象是接口,因为如果是具体类的话,那还需要Import吗? [b]Export[/b]:哪个类可以被用来Compose,也就是说这个类是不是可以用来填充的实现类,所以Export标记的是类,而不是具体的某个对象。 所以在这里calculator 使用Import 特性来标记: [Import(typeof(ICalculator))] private ICalculator calculator; 接下来MEF 的组合引擎在ComposeParts(this)的时候,就会在catalog 代表的AssemblyCatalog中查找Export特性所修饰的实现类了,找到实现类后进行Compose。 如果找不到Export特性修饰的类的话,结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645305339.png][img]http://files.jb51.net/file_images/article/201305/20130513150942111.png[/img] [/url] OK,接下来添加一个实现类,并使用Export特性来进行修饰: [Export(typeof(ICalculator))]  public class MySimpleCalculator : ICalculator  {      public string Calculate(string input)      {          return "MySimpleCalculator 处理了" + input;      }  } 运行结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645329159.png][img]http://files.jb51.net/file_images/article/201305/20130513150942112.png[/img] [/url] 当然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;     } } 运行结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/20111207064534403.png][img]http://files.jb51.net/file_images/article/201305/20130513150942113.png[/img] [/url] 因为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之间的引用需要延迟,[b]为什么需要延迟?[/b],因为IOperation需要根据IOperationData的Symbol符号来延迟创建。 也就是说,如果IOperationData的Symbol 等于 “+”,那么IOperation对象是AddOperation.如果IOperationData的Symbol等于”-”,那么IOperation对象是SubtractOperation. 那么如何保证这点呢? 关键点就在于[b]ExportMetadata attribute[/b] 上。 看下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();  } 运行结果: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645354406.png][img]http://files.jb51.net/file_images/article/201305/20130513150942114.png[/img] [/url] 因为目前定义了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;      }  } 再次运行,结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/20111207064535536.png][img]http://files.jb51.net/file_images/article/201305/20130513150942115.png[/img] [/url] 当然还可以在当前程序集下面增加- ,/,^,% 等Operation。 为了让事情更加的有趣,我打算在Debug目录下增加一个目录CalculateExtensions,然后将-,/ ..的Operation放到里面来,让MEF自动发现。 [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645357537.png][img]http://files.jb51.net/file_images/article/201305/20130513150942116.png[/img] [/url] 首先新建类库项目:SimpleCalculatorExtension 因为需要实现IOperation ,所以需要添加对SimpleCalculator项目的引用。 因为需要Export特性,所以需要添加对System.ComponentModel.Composition的引用。 整个项目的结果如下: [img]http://files.jb51.net/file_images/article/201305/20130513150942117.png[/img] 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目录应该是这样。 [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645366556.png][img]http://files.jb51.net/file_images/article/201305/20130513150942118.png[/img] [/url] 并且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());      }  } 运行结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/20111207064537734.png][img]http://files.jb51.net/file_images/article/201305/20130513150942119.png[/img] [/url] 修改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 文件夹下: 再次运行程序,输出入下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645375542.png][img]http://files.jb51.net/file_images/article/201305/20130513150942120.png[/img] [/url] [b]文章有点长,而且有点乱,最好自己动手实践下MEF,不过讲的都是MEF的基础,希望对你有所帮助,另外如果你不使用MEF,采用面向接口的编程原则的话,相信你自己也很容易实现自己的“MEF”[/b] 】: [b]以实例说话,一起体验MEF带来的可扩展性吧,Let's Rock!!![/b] 1:新建控制台程序SimpleCalculator [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645267909.png][img]http://files.jb51.net/file_images/article/201305/20130513150942110.png[/img] [/url] 在这里要实现的程序时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来实现插件的功能。 [b]Composite [/b][b]原理[/b]: 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。 [b]注:ComposeParts 是扩展方法,需要using System.ComponentModel.Composition; [/b] OK,如何Compose,在哪个Assembly中查找实现类来进行Compose已经完成了。 目前的问题是:[b]哪些类需要[/b][b]Compose??[/b] 为了回答这个问题,微软提供了Import和Export特性:  [b]Import[/b]:哪个对象需要Compose。也就是需要被实现类给填充,所以Import标记的是对象,一般该对象是接口,因为如果是具体类的话,那还需要Import吗? [b]Export[/b]:哪个类可以被用来Compose,也就是说这个类是不是可以用来填充的实现类,所以Export标记的是类,而不是具体的某个对象。 所以在这里calculator 使用Import 特性来标记: [Import(typeof(ICalculator))] private ICalculator calculator; 接下来MEF 的组合引擎在ComposeParts(this)的时候,就会在catalog 代表的AssemblyCatalog中查找Export特性所修饰的实现类了,找到实现类后进行Compose。 如果找不到Export特性修饰的类的话,结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645305339.png][img]http://files.jb51.net/file_images/article/201305/20130513150942111.png[/img] [/url] OK,接下来添加一个实现类,并使用Export特性来进行修饰: [Export(typeof(ICalculator))]  public class MySimpleCalculator : ICalculator  {      public string Calculate(string input)      {          return "MySimpleCalculator 处理了" + input;      }  } 运行结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645329159.png][img]http://files.jb51.net/file_images/article/201305/20130513150942112.png[/img] [/url] 当然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;     } } 运行结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/20111207064534403.png][img]http://files.jb51.net/file_images/article/201305/20130513150942113.png[/img] [/url] 因为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之间的引用需要延迟,[b]为什么需要延迟?[/b],因为IOperation需要根据IOperationData的Symbol符号来延迟创建。 也就是说,如果IOperationData的Symbol 等于 “+”,那么IOperation对象是AddOperation.如果IOperationData的Symbol等于”-”,那么IOperation对象是SubtractOperation. 那么如何保证这点呢? 关键点就在于[b]ExportMetadata attribute[/b] 上。 看下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();  } 运行结果: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645354406.png][img]http://files.jb51.net/file_images/article/201305/20130513150942114.png[/img] [/url] 因为目前定义了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;      }  } 再次运行,结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/20111207064535536.png][img]http://files.jb51.net/file_images/article/201305/20130513150942115.png[/img] [/url] 当然还可以在当前程序集下面增加- ,/,^,% 等Operation。 为了让事情更加的有趣,我打算在Debug目录下增加一个目录CalculateExtensions,然后将-,/ ..的Operation放到里面来,让MEF自动发现。 [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645357537.png][img]http://files.jb51.net/file_images/article/201305/20130513150942116.png[/img] [/url] 首先新建类库项目:SimpleCalculatorExtension 因为需要实现IOperation ,所以需要添加对SimpleCalculator项目的引用。 因为需要Export特性,所以需要添加对System.ComponentModel.Composition的引用。 整个项目的结果如下: [img]http://files.jb51.net/file_images/article/201305/20130513150942117.png[/img] 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目录应该是这样。 [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645366556.png][img]http://files.jb51.net/file_images/article/201305/20130513150942118.png[/img] [/url] 并且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());      }  } 运行结果如下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/20111207064537734.png][img]http://files.jb51.net/file_images/article/201305/20130513150942119.png[/img] [/url] 修改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 文件夹下: 再次运行程序,输出入下: [url=http://images.cnblogs.com/cnblogs_com/LoveJenny/201112/201112070645375542.png][img]http://files.jb51.net/file_images/article/201305/20130513150942120.png[/img] [/url] [b]文章有点长,而且有点乱,最好自己动手实践下MEF,不过讲的都是MEF的基础,希望对你有所帮助,另外如果你不使用MEF,采用面向接口的编程原则的话,相信你自己也很容易实现自己的“MEF”[/b]
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部