結城杏奈: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); Collectiontokens = 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 typeto exit).%> 2 6668%> 333 221554%> q