.Net插件编程模型:MEF和MAF

来源:互联网 发布:mac里什么浏览器最流畅 编辑:程序博客网 时间:2024/06/05 03:51


MEF和MAF都是C#下的插件编程框架,我们通过它们只需简单的配置下源代码就能轻松的实现插件编程概念,设计出可扩展的程序。这真是件美妙的事情!

MEF(Managed Extensibility Framework)

MEF的工作原理大概是这样的:首先定义一个接口,用这个接口来约束插件需要具备的职责;然后在实现接口的程序方法上面添加反射标记“[Export()]”将实现的内容导出;最后在接口的调用程序中通过属性将插件加载进来。我们还是用代码来描述吧:

1. 定义一个接口:

Csharp代码 
  1. /* 
  2.  
  3.  作者:GhostBear 
  4.  博客:http://blog.csdn.net/ghostbear   
  5.     简介:该节主要学习.net下的插件编程框架MEF(managed extensibility framework) 
  6.  
  7.  */  
  8.   
  9. using System;  
  10.   
  11. using System.Collections.Generic;  
  12.   
  13. using System.Linq;  
  14.   
  15. using System.Text;  
  16.   
  17.    
  18.   
  19. using System.Windows;  
  20.   
  21.    
  22.   
  23.    
  24.   
  25. namespace chapter28_simplecontract  
  26.   
  27. {  
  28.   
  29.     public interface ICalculator  
  30.   
  31.     {  
  32.   
  33.         IList<IOperation> GetOperations();  
  34.   
  35.         double Operate(IOperation operation, double[] operands);  
  36.   
  37.     }  
  38.   
  39.    
  40.   
  41.     public interface IOperation  
  42.   
  43.     {  
  44.   
  45.         string Name { get; }  
  46.   
  47.         int NumberOperands { get; }  
  48.   
  49.     }  
  50.   
  51.    
  52.   
  53.     public interface ICaculatorExtension  
  54.   
  55.     {  
  56.   
  57.         string Title { get; }  
  58.   
  59.         string Description { get; }  
  60.   
  61.         FrameworkElement GetUI();  
  62.   
  63.     }  
  64.   
  65. }  


2. 实现定义的接口(部分一)

Csharp代码 
  1. /*  
  2. 作者:GhostBear  
  3. 博客:http://blog.csdn.net/ghostbear  
  4. /  
Csharp代码 
  1.     [Export(typeof(ICalculator))]  
  2.   
  3.     public class Caculator:ICalculator  
  4.   
  5.     {  
  6.   
  7.    
  8.   
  9.         public IList<IOperation> GetOperations()  
  10.   
  11.         {  
  12.   
  13.             return new List<IOperation>(){  
  14.   
  15.                 new Operation{ Name="+",NumberOperands=2},  
  16.   
  17.                 new Operation{Name="-",NumberOperands=2},  
  18.   
  19.                 new Operation{Name="*",NumberOperands=2},  
  20.   
  21.                 new Operation{Name="/",NumberOperands=2}  
  22.   
  23.             };  
  24.   
  25.         }  
  26.   
  27.    
  28.   
  29.         public double Operate(IOperation operation, double[] operands)  
  30.   
  31.         {  
  32.   
  33.             double result=0;  
  34.   
  35.             switch (operation.Name)  
  36.   
  37.             {   
  38.   
  39.                 case "+":  
  40.   
  41.                     result = operands[0] + operands[1];  
  42.   
  43.                     break;  
  44.   
  45.                 case "-":  
  46.   
  47.                     result = operands[0] - operands[1];  
  48.   
  49.                     break;  
  50.   
  51.                 case "*":  
  52.   
  53.                     result = operands[0] * operands[1];  
  54.   
  55.                     break;  
  56.   
  57.                 case "/":  
  58.   
  59.                     result = operands[0] / operands[1];  
  60.   
  61.                     break;  
  62.   
  63.                 default:  
  64.   
  65.                     throw new Exception("not provide this method");  
  66.   
  67.             }  
  68.   
  69.             return result;  
  70.   
  71.         }  
  72.   
  73. }  
  74.   
  75.    
  76.   
  77.     public class Operation:IOperation  
  78.   
  79.     {  
  80.   
  81.         public string Name  
  82.   
  83.         {  
  84.   
  85.             get;  
  86.   
  87.             internal set;  
  88.   
  89.         }  
  90.   
  91.    
  92.   
  93.         public int NumberOperands  
  94.   
  95.         {  
  96.   
  97.             get;  
  98.   
  99.             internal set;  
  100.   
  101.         }  
  102.   
  103.     }  


实现定义的接口(部分二)

Csharp代码 
  1. /* 
  2.  作者:GhostBear 
  3.  博客:http://blog.csdn.net/ghostbear 
  4. */  
  5. [Export(typeof(ICalculator))]  
  6.   
  7.         public class Caculator : ICalculator  
  8.   
  9.         {  
  10.   
  11.    
  12.   
  13.             public IList<IOperation> GetOperations()  
  14.   
  15.             {  
  16.   
  17.                 return new List<IOperation>(){  
  18.   
  19.                 new Operation{ Name="+",NumberOperands=2},  
  20.   
  21.                 new Operation{Name="-",NumberOperands=2},  
  22.   
  23.                 new Operation{Name="*",NumberOperands=2},  
  24.   
  25.                 new Operation{Name="/",NumberOperands=2},  
  26.   
  27.                 new Operation{Name="%",NumberOperands=2},  
  28.   
  29.                 new Operation{Name="**",NumberOperands=1},  
  30.   
  31.                   
  32.   
  33.             };  
  34.   
  35.             }  
  36.   
  37.    
  38.   
  39.             public double Operate(IOperation operation, double[] operands)  
  40.   
  41.             {  
  42.   
  43.                 double result = 0;  
  44.   
  45.                 switch (operation.Name)  
  46.   
  47.                 {  
  48.   
  49.                     case "+":  
  50.   
  51.                         result = operands[0] + operands[1];  
  52.   
  53.                         break;  
  54.   
  55.                     case "-":  
  56.   
  57.                         result = operands[0] - operands[1];  
  58.   
  59.                         break;  
  60.   
  61.                     case "*":  
  62.   
  63.                         result = operands[0] * operands[1];  
  64.   
  65.                         break;  
  66.   
  67.                     case "/":  
  68.   
  69.                         result = operands[0] / operands[1];  
  70.   
  71.                         break;  
  72.   
  73.                     case "%":  
  74.   
  75.                         result=operands[0]%operands[1];  
  76.   
  77.                         break;  
  78.   
  79.                     case "**":  
  80.   
  81.                         result=operands[0]*operands[0];  
  82.   
  83.                         break;  
  84.   
  85.                     default:  
  86.   
  87.                         throw new Exception("not provide this method");  
  88.   
  89.                 }  
  90.   
  91.                 return result;  
  92.   
  93.             }  
  94.   
  95.         }  
  96.   
  97.    
  98.   
  99.         public class Operation : IOperation  
  100.   
  101.         {  
  102.   
  103.             public string Name  
  104.   
  105.             {  
  106.   
  107.                 get;  
  108.   
  109.                 internal set;  
  110.   
  111.             }  
  112.   
  113.    
  114.   
  115.             public int NumberOperands  
  116.   
  117.             {  
  118.   
  119.                 get;  
  120.   
  121.                 internal set;  
  122.   
  123.             }  
  124.   
  125.         }  
  126.   
  127.    


分析:

标记“[Export(typeof(ICalculator))]”声明表达的意思是:这个类可以编译为插件,并能放入插件容器“ICalculator”中。这里需要注意的是:部分一和部分二的代码分布在不同的程序集中。导出的插件不一定必须是以类的形式,也可以是方法。

通过导出方法来生成插件:

Csharp代码 
  1.     /* 
  2.  作者:GhostBear 
  3.  博客:http://blog.csdn.net/ghostbear 
  4.    */  
  5. public class Bomb  
  6.   
  7.     {  
  8.   
  9.         [Export("Bomb")]  
  10.   
  11.         public void Fire()  
  12.   
  13.         {  
  14.   
  15.             Console.WriteLine("you are dead!!!");  
  16.   
  17.         }  
  18.   
  19.     }  


插件的调用者:

Csharp代码 
  1. /* 
  2.  
  3.  
  4.  作者:GhostBear 
  5.  博客:http://blog.csdn.net/ghostbear 
  6.  
  7.  *  简介:该节主要学习.net下的插件编程框架MEF(managed extensibility framework) 
  8.  
  9.  */  
  10.   
  11. using System;  
  12.   
  13. using System.Collections.Generic;  
  14.   
  15. using System.Linq;  
  16.   
  17. using System.Text;  
  18.   
  19.    
  20.   
  21. using System.ComponentModel.Composition;  
  22.   
  23. using System.ComponentModel.Composition.Hosting;  
  24.   
  25.    
  26.   
  27. using chapter28_simplecontract;  
  28.   
  29.    
  30.   
  31. namespace chapter28  
  32.   
  33. {  
  34.   
  35.     class Program  
  36.   
  37.     {  
  38.   
  39.    
  40.   
  41.         [ImportMany(typeof(ICalculator))]  
  42.   
  43.         public IEnumerable<ICalculator> Calculators { getset; }  
  44.   
  45.    
  46.   
  47.         [Import("Bomb")]  
  48.   
  49.         public Action Bomb { getset; }  
  50.   
  51.    
  52.   
  53.    
  54.   
  55.           
  56.   
  57.         static void Main(string[] args)  
  58.   
  59.         {  
  60.   
  61.             Program pro = new Program();  
  62.   
  63.             pro.Run();  
  64.   
  65.             pro.Run2();  
  66.   
  67.         }  
  68.   
  69.    
  70.   
  71.         public void Run()  
  72.   
  73.         {  
  74.   
  75.             var catalog = new DirectoryCatalog("c:\\plugins");  
  76.   
  77.             var container = new CompositionContainer(catalog);  
  78.   
  79.             try  
  80.   
  81.             {  
  82.   
  83.                 container.ComposeParts(this);  
  84.   
  85.             }  
  86.   
  87.             catch (Exception ex)  
  88.   
  89.             {  
  90.   
  91.                 Console.WriteLine(ex.Message);  
  92.   
  93.                 return;  
  94.   
  95.             }  
  96.   
  97.             ICalculator myCalculator = Calculators.ToList<ICalculator>()[1];  
  98.   
  99.               
  100.   
  101.    
  102.   
  103.             var operations = myCalculator.GetOperations();  
  104.   
  105.             var operationsDict = new SortedList<string, IOperation>();  
  106.   
  107.             foreach(IOperation item in operations)  
  108.   
  109.             {  
  110.   
  111.                 Console.WriteLine("Name:{0},number operands:{1}"  
  112.   
  113. , item.Name, item.NumberOperands);  
  114.   
  115.                 operationsDict.Add(item.Name, item);  
  116.   
  117.             }  
  118.   
  119.             Console.WriteLine();  
  120.   
  121.             string selectedOp = null;  
  122.   
  123.    
  124.   
  125.             do  
  126.   
  127.             {  
  128.   
  129.                 try  
  130.   
  131.                 {  
  132.   
  133.                     Console.Write("Operation?");  
  134.   
  135.                     selectedOp = Console.ReadLine();  
  136.   
  137.                     if (selectedOp.ToLower() == "exit"  
  138.   
  139.                                      || !operationsDict.ContainsKey(selectedOp))  
  140.   
  141.                     {  
  142.   
  143.                         continue;  
  144.   
  145.                     }  
  146.   
  147.                     var operation = operationsDict[selectedOp];  
  148.   
  149.                     double[] operands = new double[operation.NumberOperands];  
  150.   
  151.                     for (int i = 0; i < operation.NumberOperands; i++)  
  152.   
  153.                     {  
  154.   
  155.                         Console.WriteLine("\t operand {0}?", i + 1);  
  156.   
  157.                         string selectedOperand = Console.ReadLine();  
  158.   
  159.                         operands[i] = double.Parse(selectedOperand);  
  160.   
  161.                     }  
  162.   
  163.                     Console.WriteLine("calling calculator");  
  164.   
  165.                     double result = myCalculator.Operate(operation, operands);  
  166.   
  167.                     Console.WriteLine("result:{0}", result);  
  168.   
  169.                 }  
  170.   
  171.                 catch (Exception ex)  
  172.   
  173.                 {  
  174.   
  175.                     Console.WriteLine(ex.Message);  
  176.   
  177.                     Console.WriteLine();  
  178.   
  179.                     continue;  
  180.   
  181.                 }  
  182.   
  183.             } while (selectedOp != "exit");  
  184.   
  185.         }  
  186.   
  187.    
  188.   
  189.         public void Run2()  
  190.   
  191.         {  
  192.   
  193.             var catalog = new DirectoryCatalog("c:\\plugins");  
  194.   
  195.             var container = new CompositionContainer(catalog);  
  196.   
  197.    
  198.   
  199.             container.ComposeParts(this);  
  200.   
  201. Bomb.Invoke();  
  202.   
  203.             Console.ReadKey();  
  204.   
  205.         }  
  206.   
  207.     }  
  208.   
  209. }  


分析:

标记“[ImportMany(typeof(ICalculator))]”,该声明表达的意图是:将所有声明了标记“[Export(typeof(ICalculator))]”的程序集加载进容器。这里“[ImportMany]和”[Import]”的区别就是:前者的容器可以存放多个插件,而后者只能存放一个。

光声明“[Import()]”和”[Export()]”标记是不行的,还必须通过下面的代码将这两个标记的功能联合起来:

Csharp代码 
  1.  //DirectoryCatalog表示这类插件会存放在系统的哪个文件夹下  
  2.   
  3. var catalog = new DirectoryCatalog("c:\\plugins");  
  4.   
  5.             var container = new CompositionContainer(catalog);  
  6.   
  7.             try  
  8.   
  9.             {  
  10.   
  11. //将存放在目录中的插件按“[Export()]和[Import()]”规则装载进当前  
  12.   
  13. //类中。  
  14.   
  15.                 container.ComposeParts(this);  
  16.   
  17.             }  
  18.   
  19.             catch (Exception ex)  
  20.   
  21.             {  
  22.   
  23.                 Console.WriteLine(ex.Message);  
  24.   
  25.                 return;  
  26.   
  27.             }  


执行结果

Name:+,number operands:2

Name:-,number operands:2

Name:*,number operands:2

Name:/,number operands:2

Operation?+

operand 1?

1

operand 2?

1

calling calculator

result:2

Operation?exit

you are dead!!!

MAF(Managed Addin Framework)

MAF也是.Net为我们提供的一个“插件编程”解决方案。它比MEF复杂,需要配置很多元素。但它也有些优点:1.宿主程序和插件程序可以进行隔离,以此降低运行插件所带来的风险;2。MAF的设计是基于7个程序集组成的管道,这些管道部分可以单独更换,这些管道的详细情况见下图。

图1

使用MAF是需要有些细节需要注意:组成管道的7个程序集在系统中的保存路径有格式要求,并且没个保存它的文件夹内只运行同时出现一个程序集。具体情况如下图所示:

图2

图3

图4

图5

下面我们来看一个小Demo吧,这个demo一共有7个项目,它们分别对应图1描述的管道中的7个部分。具体情况见下图。

图6

插件:Addin_1,Addin_2

插件视图:AddinSideView

插件适配器:AddinSideAdapter

协定:IContract

宿主视图:HostSideView

宿主适配器:HostSideAdapter

宿主程序:Host

程序代码

Addin_1

Csharp代码 
  1. /* 
  2.  
  3.  
  4.  作者:GhostBear 
  5.  博客:http://blog.csdn.net/ghostbear 
  6.     简介:测试MAF,这段代码是用来定义一个插件的。这个插件可以在宿主程序 
  7.      中动态加载。 
  8.  
  9.  */  
  10.   
  11. using System;  
  12.   
  13. using System.Collections.Generic;  
  14.   
  15. using System.Linq;  
  16.   
  17. using System.Text;  
  18.   
  19.    
  20.   
  21. using System.AddIn;  
  22.   
  23. using System.AddIn.Pipeline;  
  24.   
  25.    
  26.   
  27. namespace Addin_1  
  28.   
  29. {  
  30.   
  31. [AddIn("Helloworld",Description="this is helloworld addin"  
  32.   
  33. ,Publisher="GhostBear",Version="1.0")]  
  34.   
  35.     public class Addin_1:AddinSideView.AddinSideView  
  36.   
  37.     {  
  38.   
  39.    
  40.   
  41.         public string Say()  
  42.   
  43.         {  
  44.   
  45.             return "Helloworld";  
  46.   
  47.         }  
  48.   
  49.     }  
  50.   
  51. }  


Addin_2

Csharp代码 
  1. /* 
  2.  作者:GhostBear 
  3.  博客:http://blog.csdn.net/ghostbear 
  4. */  
  5. using System;  
  6.   
  7. using System.Collections.Generic;  
  8.   
  9. using System.Linq;  
  10.   
  11. using System.Text;  
  12.   
  13.    
  14.   
  15. using System.AddIn;  
  16.   
  17.    
  18.   
  19. namespace Addin_2  
  20.   
  21. {  
  22.   
  23. [AddIn("SuperBomb",Description="This is a bigger bomb"  
  24.   
  25. ,Publisher="SuperWorker",Version="1.0.0.0")]  
  26.   
  27.     public class Addin_2:AddinSideView.AddinSideView  
  28.   
  29.     {  
  30.   
  31.         public string Say()  
  32.   
  33.         {  
  34.   
  35.             return "B--O--M--B";  
  36.   
  37.         }  
  38.   
  39.     }  
  40.   
  41. }  


AddinSideView

Csharp代码 
  1. /* 
  2.  
  3.  
  4.  作者:GhostBear 
  5.  博客:http://blog.csdn.net/ghostbear 
  6.  
  7. *   简介:测试MAF,这段代码是定义插件端的视图类,该视图类的方法和属性必须与协定一致。 
  8.  
  9.  */  
  10.   
  11. using System;  
  12.   
  13. using System.Collections.Generic;  
  14.   
  15. using System.Linq;  
  16.   
  17. using System.Text;  
  18.   
  19.    
  20.   
  21.    
  22.   
  23. using System.AddIn.Pipeline;  
  24.   
  25. namespace AddinSideView  
  26.   
  27. {  
  28.   
  29.     [AddInBase()]  
  30.   
  31.     public interface AddinSideView  
  32.   
  33.     {  
  34.   
  35.         string Say();  
  36.   
  37.     }  
  38.   
  39. }  


AddinSideAdapter

Csharp代码 
  1. /* 
  2.  
  3.  
  4.  作者:GhostBear 
  5.  博客:http://blog.csdn.net/ghostbear 
  6.  
  7. *   简介:测试MAF,这段代码是插件端的适配器类,它用来实现插件端视图类。 
  8.  
  9.  *         并组合协定。这样就能让插件和协定解耦,如果插件有所修改就换掉 
  10.  
  11.  *         该适配器类就可以了。 
  12.  
  13.  */  
  14.   
  15.    
  16.   
  17. using System;  
  18.   
  19. using System.Collections.Generic;  
  20.   
  21. using System.Linq;  
  22.   
  23. using System.Text;  
  24.   
  25.    
  26.   
  27. using System.AddIn.Pipeline;  
  28.   
  29.    
  30.   
  31.    
  32.   
  33. namespace AddinSideAdapter  
  34.   
  35. {  
  36.   
  37.     [AddInAdapter]  
  38.   
  39.     public class AddinSideAdapter : ContractBase,IContract.IMyContract  
  40.   
  41.     {  
  42.   
  43.         private AddinSideView.AddinSideView _handler;  
  44.   
  45.         public AddinSideAdapter(AddinSideView.AddinSideView handler)  
  46.   
  47.         {  
  48.   
  49.             this._handler = handler;  
  50.   
  51.         }  
  52.   
  53.    
  54.   
  55.         public string Say()  
  56.   
  57.         {  
  58.   
  59.             return this._handler.Say();  
  60.   
  61.         }  
  62.   
  63.     }  
  64.   
  65. }  
  66.   
  67.    


IContract

Csharp代码 
  1. /* 
  2.  
  3.  
  4.  作者:GhostBear 
  5.  博客:http://blog.csdn.net/ghostbear 
  6.  
  7.      简介:测试MAF,这段代码是定义协定。 
  8.  
  9.  */  
  10.   
  11.    
  12.   
  13. using System;  
  14.   
  15. using System.Collections.Generic;  
  16.   
  17. using System.Linq;  
  18.   
  19. using System.Text;  
  20.   
  21.    
  22.   
  23. using System.AddIn.Pipeline;  
  24.   
  25. using System.AddIn.Contract;  
  26.   
  27.    
  28.   
  29. namespace IContract  
  30.   
  31. {  
  32.   
  33.     [AddInContract]  
  34.   
  35.     public interface IMyContract:System.AddIn.Contract.IContract  
  36.   
  37.     {  
  38.   
  39.         string Say();  
  40.   
  41.     }  
  42.   
  43. }  
  44.   
  45.    

HostSideView

Csharp代码 
  1. /* 
  2.  
  3.  
  4.  作者:GhostBear 
  5.  博客:http://blog.csdn.net/ghostbear 
  6.  
  7.     简介:测试MAF,这段代码用来定义宿主段的视图类,该类的所有方法和属性需与协定类一致。 
  8.  
  9.  */  
  10.   
  11. using System;  
  12.   
  13. using System.Collections.Generic;  
  14.   
  15. using System.Linq;  
  16.   
  17. using System.Text;  
  18.   
  19.    
  20.   
  21. namespace HostSideView  
  22.   
  23. {  
  24.   
  25.     public interface HostSideView  
  26.   
  27.     {  
  28.   
  29.         string Say();  
  30.   
  31.     }  
  32.   
  33. }  


HostSideAdapter

Csharp代码 
  1. /* 
  2.  
  3.  作者:GhostBear 
  4.  博客:http://blog.csdn.net/ghostbear 
  5.     简介:测试MAF,这段代码用来定义宿主端的适配器类。该类实现宿主端的 
  6.     视图类并组合协定。 
  7.  
  8.  */  
  9.   
  10.    
  11.   
  12. using System;  
  13.   
  14. using System.Collections.Generic;  
  15.   
  16. using System.Linq;  
  17.   
  18. using System.Text;  
  19.   
  20.    
  21.   
  22. using System.AddIn.Pipeline;  
  23.   
  24.    
  25.   
  26.    
  27.   
  28.    
  29.   
  30. namespace HostSideAdapter  
  31.   
  32. {  
  33.   
  34.     [HostAdapter()]  
  35.   
  36.     public class HostSideAdapter:HostSideView.HostSideView  
  37.   
  38.     {  
  39.   
  40.    
  41.   
  42.         private IContract.IMyContract _contract;  
  43.   
  44.         //这行代码重要  
  45.   
  46.         private System.AddIn.Pipeline.ContractHandle _handle;  
  47.   
  48.         public HostSideAdapter(IContract.IMyContract contract)  
  49.   
  50.         {  
  51.   
  52.             this._contract = contract;  
  53.   
  54.             this._handle = new ContractHandle(contract);  
  55.   
  56.           
  57.   
  58.         }  
  59.   
  60.    
  61.   
  62.    
  63.   
  64.         public string Say()  
  65.   
  66.         {  
  67.   
  68.             return this._contract.Say();  
  69.   
  70.         }  
  71.   
  72.     }  
  73.   
  74. }  
  75.   
  76.    


Host

Csharp代码 
  1. /* 
  2.  作者:GhostBear 
  3.  博客:http://blog.csdn.net/ghostbear 
  4.     简介:测试MAF,这段代码是宿主程序。该程序可以针对保存在某个目录下的插件来进行选择性调用。 
  5.  
  6.  */  
  7.   
  8.    
  9.   
  10. using System;  
  11.   
  12. using System.Collections.Generic;  
  13.   
  14. using System.Linq;  
  15.   
  16. using System.Text;  
  17.   
  18.    
  19.   
  20.    
  21.   
  22. using System.Collections;  
  23.   
  24. using System.Collections.ObjectModel;  
  25.   
  26.    
  27.   
  28. using System.AddIn.Hosting;  
  29.   
  30.    
  31.   
  32. using HostSideView;  
  33.   
  34.    
  35.   
  36. namespace Host  
  37.   
  38. {  
  39.   
  40.     class Program  
  41.   
  42.     {  
  43.   
  44.         static void Main(string[] args)  
  45.   
  46.         {  
  47.   
  48.             string path = @"D:\学习文档\c#\c#高级编程7\MAF\MAF";  
  49.   
  50.             string[] warnings = AddInStore.Update(path);  
  51.   
  52.    
  53.   
  54.             foreach (var tmp in warnings)  
  55.   
  56.             {  
  57.   
  58.                 Console.WriteLine(tmp);  
  59.   
  60.             }  
  61.   
  62.       //发现  
  63.   
  64.       var tokens = AddInStore.FindAddIns(typeof(HostSideView.HostSideView), path);  
  65.   
  66.    
  67.   
  68.             Console.WriteLine("当前共有{0}个插件可以选择。它们分别为:",tokens.Count);  
  69.   
  70.    
  71.   
  72.             var index = 1;  
  73.   
  74.             foreach (var tmp in tokens)  
  75.   
  76.             {  
  77.   
  78.                 Console.WriteLine(string.Format("[{4}]名称:{0},描述:{1},版本:{2},发布者:{3}", tmp.Name, tmp.Description, tmp.Version, tmp.Publisher,index++));  
  79.   
  80.             }  
  81.   
  82.    
  83.   
  84.    
  85.   
  86.             var token = ChooseCalculator(tokens);  
  87.   
  88.               
  89.   
  90. //隔离和激活插件  
  91.   
  92.             AddInProcess process=new AddInProcess(Platform.X64);  
  93.   
  94.             process.Start();  
  95.   
  96.             var addin = token.Activate<HostSideView.HostSideView>(process, AddInSecurityLevel.FullTrust);  
  97.   
  98.             Console.WriteLine("PID:{0}",process.ProcessId);  
  99.   
  100.             //调用插件  
  101.   
  102. Console.WriteLine(addin.Say());  
  103.   
  104.    
  105.   
  106.             Console.ReadKey();  
  107.   
  108.         }  
  109.   
  110.    
  111.   
  112.         private static AddInToken ChooseCalculator(Collection<AddInToken> tokens)  
  113.   
  114.         {  
  115.   
  116.             if (tokens.Count == 0)  
  117.   
  118.             {  
  119.   
  120.                 Console.WriteLine("No calculators are available");  
  121.   
  122.                 return null;  
  123.   
  124.             }  
  125.   
  126.             Console.WriteLine("Available Calculators: ");  
  127.   
  128.             // Show the token properties for each token in the AddInToken collection   
  129.   
  130.             // (tokens), preceded by the add-in number in [] brackets.  
  131.   
  132.             int tokNumber = 1;  
  133.   
  134.             foreach (AddInToken tok in tokens)  
  135.   
  136.             {  
  137.   
  138.                 Console.WriteLine(String.Format("\t[{0}]: {1} - {2}\n\t{3}\n\t\t {4}\n\t\t {5} - {6}",  
  139.   
  140.                     tokNumber.ToString(),  
  141.   
  142.                     tok.Name,  
  143.   
  144.                     tok.AddInFullName,  
  145.   
  146.                     tok.AssemblyName,  
  147.   
  148.                     tok.Description,  
  149.   
  150.                     tok.Version,  
  151.   
  152.                     tok.Publisher));  
  153.   
  154.                 tokNumber++;  
  155.   
  156.             }  
  157.   
  158.             Console.WriteLine("Which calculator do you want to use?");  
  159.   
  160.             String line = Console.ReadLine();  
  161.   
  162.             int selection;  
  163.   
  164.             if (Int32.TryParse(line, out selection))  
  165.   
  166.             {  
  167.   
  168.                 if (selection <= tokens.Count)  
  169.   
  170.                 {  
  171.   
  172.                     return tokens[selection - 1];  
  173.   
  174.                 }  
  175.   
  176.             }  
  177.   
  178.             Console.WriteLine("Invalid selection: {0}. Please choose again.", line);  
  179.   
  180.             return ChooseCalculator(tokens);  
  181.   
  182.         }  
  183.   
  184.     }  
  185.   
  186. }  
  187.   
  188.    

分析

在上面的7个程序集,起解耦作用的关键还是2个适配器类。调用程序不直接调用协定,而是通过通过调用这2个适配器来间接调用协定。

小结

MEF和MAF为我们实现“插件编程”提供了2中选择,它们设计的出发点也是完全不同的。在使用它们的时候还是需要更加具体需求来权衡使用。

原创粉丝点击