結城杏奈:C Sharp与.net学习笔记(三)

来源:百度文库 编辑:偶看新闻 时间:2024/04/30 00:42:10

先简单了解一下C#下插件框架。插件一般就是定义了某个特定接口的并被动态加载的动态库。应用程序启动后,可以查找(比如某个特定目录)、动态加载、识别(某个特定接口)、使用插件(调用接口函数等)。

现在.net库中有了两套插件的框架:

MAF: Managed Add-in Framework

从VS2008(.NET3.5)开始

MEF: Managed Extensibility Framework

从VS2010(.NET4.0)开始

这两个的优劣,网上已经有了很多的讨论。最主要的可能就是:(fixme)

  • MAF使用比较繁琐,但可以将主程序和插件完全隔离
    • 即使某个插件崩溃了主程序也不受影响。可以动态更新和卸载插件
    • 不同版本的插件、主程序兼容性容易实现。
  • MEF使用简单,主程序和插件不需要明确的区分
    • 似乎大家都更看好这个,VS2010自身采用的也是MEF?

MAF

主程序

程序接口

 

接口

 

插件接口

插件

Host

Host views of Add-ins

 

Contracts

 

Add-In views

Add-In

 

adapters

 

adapters

  

看起来好复杂啊,但似乎还不是太难理解:

  • 对于传统方式的插件,我们定义一个接口,插件提供该接口实现,程序通过接口操作
  • 在这儿,首先定义一个接口(称为Contract),但是程序和插件都不用关心这个Contract具体是什么样子,它们只关心各自的接口(View),View和Contract之间通过适配器进行适配。

凭空多出这个多东西,而且应该程序要能找到它们,故MAF都它们的位置有要求:

类别

位置(某个共同目录的子目录)

HostSideAdapters

PathOfDbzhang\HostSideAdapters

Contracts

PathOfDbzhang\Contracts

AddInSideAdapters

PathOfDbzhang\AddInSideAdapters

AddInViews

PathOfDbzhang\AddInViews

AddIns

PathOfDbzhang\AddIns\XXXX

MAF 例子

这个东西太麻烦了,恩,抛开VS集成环境,直接使用命令行来试试一个简单的例子

源文件

==>

最终产物

说明

Application.cs

 

Application.exe

我们的程序

HostAddInView.cs

 

MyHostAddInView.dll

HostSideAdapter.cs

 

HostSideAdapters/ MyHostSideAdapter.dll

 

AddInContract.cs

 

Contracts/ MyAddInContract.dll

接口

AddInSideAdapter.cs

 

AddInSideAdapters/ MyAddInSideAdapter.dll

 

AddInView.cs

 

AddInViews/ MyAddInView.dll

 

Addin1.cs

 

AddIns/XXXX/Addin1.dll

插件

应用程序

  • 定义程序操作的接口HostAddInView.cs :

namespace CalcHVAs{    public abstract class Calculator    {        public abstract double Calc(double a, double b);    }}
  • 定义我们的程序 Application.cs(它只操作我们前面刚定义的接口):

using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.AddIn.Hosting;using CalcHVAs;namespace MathHost{    class Program    {        static void Main()        {            // Assumes that the current directory is the addins root directory.             String addInRoot = Environment.CurrentDirectory;            // Search for addins.            AddInStore.Update(addInRoot);            Collection tokens = AddInStore.FindAddIns(typeof(Calculator), addInRoot);            // Select an add-in.            if (tokens.Count == 0) {                Console.WriteLine("No plugins available.");                return;            }            AddInToken calcToken = ChooseCalculator(tokens);            //Activate the AddIn in a new application domain with the Internet trust level.            Calculator calc = calcToken.Activate(AddInSecurityLevel.Internet);            //Run the add-in.            RunCalculator(calc);        }        private static AddInToken ChooseCalculator(Collection tokens)        {            Console.WriteLine("Available Plugins: ");            int tokNo = 0;            foreach (AddInToken tok in tokens) {                Console.WriteLine("\t[{0}]: {1}", tokNo.ToString(), tok.AssemblyName);                tokNo++;            }            Console.WriteLine("Which calculator do you want to use?");            String line = Console.ReadLine();            int selection;            if (Int32.TryParse(line, out selection)) {                if (selection < tokens.Count) {                    return tokens[selection];                }            }            return tokens[0];        }        private static void RunCalculator(Calculator calc)        {            Console.Write("Input two numbers such as 2 3 (Or type  to exit). \n%> ");            String line = Console.ReadLine();            while (!line.Equals("q")) {                try {                    String[] parts = line.Split(' ');                    double a = Double.Parse(parts[0]);                    double b = Double.Parse(parts[1]);                    Console.Write("{0}\n%> ", calc.Calc(a, b));                } catch {                    Console.Write("Invalid command: {0} \n%> ", line);                }                line = Console.ReadLine();            }        }    }}

插件

  • 定义插件需要实现的接口 AddInView.cs

using System;using System.AddIn.Pipeline;namespace CalcAddInViews{    [AddInBase()]    public abstract class Calculator    {        public abstract double Calc(double a, double b);    }}
  • 实现该接口Addin1.cs

using System.AddIn;using CalcAddInViews;namespace CalcAddIns{    [AddIn("Dbzhang800 AddIn",Version="1.0.0.0")]    public class AddInCalcV1 : Calculator    {        public override double Calc(double a, double b)        {            return a + b;        }    }}

接口适配

  • 定义接口 AddInContract.cs :

using System.AddIn.Contract;using System.AddIn.Pipeline;namespace CalculatorContracts{    [AddInContract]    public interface ICalc1Contract : IContract    {        double Calc(double a, double b);    }}

将应用程序和接口的接口和该接口分别进行适配

  • HostSideAdpater.cs

using System;using System.AddIn.Pipeline;using CalcHVAs;using CalculatorContracts;namespace CalcHostSideAdapters{    [HostAdapterAttribute()]    public class CalculatorContractToViewHostSideAdapter : Calculator    {        private ICalc1Contract _contract;        private System.AddIn.Pipeline.ContractHandle _handle;            public CalculatorContractToViewHostSideAdapter(ICalc1Contract contract)         {                _contract = contract;                _handle = new ContractHandle(contract);        }            public override double Calc(double a, double b)        {                return _contract.Calc(a, b);        }    }}
  • AddInSideAdapter.cs

using System;using System.AddIn.Pipeline;using CalcAddInViews;using CalculatorContracts;namespace CalcAddInSideAdapters{    [AddInAdapter()]    public class CalculatorViewToContractAddInSideAdapter : ContractBase, ICalc1Contract    {        private Calculator _view;        public CalculatorViewToContractAddInSideAdapter(Calculator view)        {            _view = view;        }        public virtual double Calc(double a, double b)        {            return _view.Calc(a, b);        }    }}

编译

前面7个文件,要分别编译成7个dll/exe文件,还好,每一只需要一个csc命令即可,写成一个.bat文件,如下

set libPath="C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5"csc /target:library /out:Contracts\MyAddInContract.dll  /lib:%libPath% /r:System.AddIn.Contract.dll;System.AddIn.dll  AddInContract.cscsc /target:library  /out:AddInViews\MyAddInView.dll  /lib:%libPath% /r:System.AddIn.dll  AddInView.cscsc /target:library HostAddInView.cscsc /target:library  /out:AddInSideAdapters\MyAddInSideAdpter.dll /lib:%libPath% /r:System.AddIn.dll;System.AddIn.Contract.dll;AddInViews\MyAddInView.dll;Contracts\MyAddInContract.dll AddInSideAdapter.cscsc /target:library  /out:HostSideAdapters\MyHostSideAdpter.dll /lib:%libPath% /r:System.AddIn.dll;System.AddIn.Contract.dll;HostAddInView.dll;Contracts\MyAddInContract.dll HostSideAdapter.cscsc /lib:%libPath% /r:System.AddIn.dll;HostAddInView.dll Application.cscsc /target:library  /out:AddIns\CalcV1\MyAddIn1.dll /lib:%libPath% /r:System.AddIn.dll;System.AddIn.Contract.dll;AddInViews\MyAddInView.dll AddIn1.cs

结果

看看运行结果:

E:\CalculatorV1> applicationAvailable Plugins:        [0]: MyAddIn1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=nullWhich calculator do you want to use?0Input two numbers such as 2 3 (Or type  to exit).%> 2 6668%> 333 221554%> q