更新:2010 年 7 月
本主题提供了 .NET Framework 4 中引入的 Managed Extensibility Framework 的概述。
本主题包括下列各节。
通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。
您的应用程序必须包含大量可能需要的较小组件,并负责创建和运行这些组件。
同样存在问题的还有,您可能没有对组件的源代码的访问权,因为这些组件可能是由第三方开发的,而出于相同的原因,您也不允许第三方访问您的代码。
这一方法可解决需要源代码访问权的问题,但仍具有自己的难点。
这意味着,确保组件正确无误成为了一个日常维护问题,尤其是在执行更新操作的是最终用户而非开发人员的情况下。
如果应用程序架构师未预计到需要某项通信,则通常是无法进行相应的通信的。
这样就很难在多个应用程序中使用同一个组件,另外,在为组件创建测试框架时也会造成问题。
创建一个部件时,MEF 组合引擎会使其导入与其他部件提供的内容相符合。
因此,没有必要仔细指定应何时以及如何加载扩展。
例如,可以将许多组件的公用服务分解到单独的部件中,以便于修改或替换。
利用此模型,还可以轻松地开发独立于应用程序的测试工具来测试扩展组件。
通过这种方式,扩展组件本身是自动可扩展的。
可以在客户端应用程序中使用 MEF(无论应用程序使用的是 Windows 窗体、WPF,还是任何其他技术),也可以在使用 ASP.NET 的服务器应用程序中使用 MEF。
这两个框架可以顺利地进行互操作,并且单个应用程序可以同时利用这两个框架。
通过使用 MEF,您将能够在不更改应用程序代码的情况下添加新的运算符。
SimpleCalculator sample(SimpleCalculator 示例)。
|
|
|---|
|
Managed Extensibility Framework。 |
Public 关键字。
CompositionContainer,您可以将此类型用于 SimpleCalculator。
Program 类:
应用程序开发人员可以轻松地创建用于从其他源(如 Web 服务)发现部件的新目录。
Program 类:
private Program() { //An aggregate catalog that combines multiple catalogs var catalog = new AggregateCatalog(); //Adds all the parts found in the same assembly as the Program class catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly)); //Create the CompositionContainer with the parts in the catalog _container = new CompositionContainer(catalog); //Fill the imports of this object try { this._container.ComposeParts(this); } catch (CompositionException compositionException) { Console.WriteLine(compositionException.ToString()); } }
Program 没有要填充的导入。
Program 的控制台输入和输出)与计算器的逻辑相分离。
Program 类中:
此特性将某个对象声明为一个导入;也就是说,在组合对象时将由组合引擎对它进行填充。
MEF 将会自动假定协定基于导入的类型,除非您显式指定协定将基于的类型。)
SimpleCalculator 命名空间中:
SimpleCalculator 命名空间中:
typeof(MySimpleCalculator) 的协定进行导出时会造成不匹配,将不会填充导入;协定需要完全匹配。
MySimpleCalculator 对象填充。
Main 方法来填充用户界面逻辑的其余部分。
Main 方法中:
static void Main(string[] args) { Program p = new Program(); //Composition is performed in the constructor String s; Console.WriteLine("Enter Command:"); while (true) { s = Console.ReadLine(); Console.WriteLine(p.calculator.Calculate(s)); } }
剩下的所有工作将在部件中完成。
ImportManyAttribute 特性。
MySimpleCalculator 类中:
IOperationData 对象(表示运算的元数据)。
SimpleCalculator 命名空间中:
public interface IOperation { int Operate(int left, int right); } public interface IOperationData { Char Symbol { get; } }
SimpleCalculator 命名空间中:
[Export(typeof(IOperation))] [ExportMetadata("Symbol", '+')] class Add: IOperation { public int Operate(int left, int right) { return left + right; } }
(这是访问 MEF 中的元数据的方法之一。)
(不过,可以将导入声明为可选导入或为其分配默认值。)
MySimpleCalculator 方法:
public String Calculate(String input) { int left; int right; Char operation; int fn = FindFirstNonDigit(input); //finds the operator if (fn < 0) return "Could not parse command."; try { //separate out the operands 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!"; }
Operate 方法并返回结果。
MySimpleCalculator 类中:
private int FindFirstNonDigit(String s) { for (int i = 0; i < s.Length; i++) { if (!(Char.IsDigit(s[i]))) return i; } return -1; }
任何其他运算符都将导致生成“Operation Not Found!”(运算未找到!)消息。
DirectoryCatalog,以便在目录以及目录自己的程序集中搜索部件。
该新项目将编译到单独的程序集中。
\SimpleCalculator\Extensions\)。
Program 构造函数:
catalog.Catalogs.Add(new DirectoryCatalog("C:\\SimpleCalculator\\SimpleCalculator\\Extensions"));
DirectoryCatalog 将在 Extensions 目录下的任何程序集中找到的所有部件都添加到组合容器中。
然后,将下面的类添加到 ExtendedOperations 类文件中:
[Export(typeof(SimpleCalculator.IOperation))] [ExportMetadata("Symbol", '%')] public class Mod : SimpleCalculator.IOperation { public int Operate(int left, int right) { return left % right; } }
ImportAttribute 相同。
测试新 Mod (%) 运算符。
本主题介绍了 MEF 的基本概念。
-
部件、目录和组合容器
组合容器使用目录提供的部件来执行组合操作(即,将导入绑定到导出)。
-
导入和导出
每个导入都按其协定的方式与一组导出匹配。
SimpleCalculator sample(SimpleCalculator 示例)。
System.ComponentModel.Composition 命名空间。
|
日期 |
修订记录 |
原因 |
|---|---|---|
|
2010 年 7 月 |
添加了指向下载示例的链接。 |
客户反馈 |