http://msdn.microsoft.com/zh-cn/library/dd460648.aspx
.NET Framework 4

 

更新:2010 年 7 月

通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。

您的应用程序必须包含大量可能需要的较小组件,并负责创建和运行这些组件。

同样存在问题的还有,您可能没有对组件的源代码的访问权,因为这些组件可能是由第三方开发的,而出于相同的原因,您也不允许第三方访问您的代码。

这一方法可解决需要源代码访问权的问题,但仍具有自己的难点。

这意味着,确保组件正确无误成为了一个日常维护问题,尤其是在执行更新操作的是最终用户而非开发人员的情况下。

如果应用程序架构师未预计到需要某项通信,则通常是无法进行相应的通信的。

这样就很难在多个应用程序中使用同一个组件,另外,在为组件创建测试框架时也会造成问题。

创建一个部件时,MEF 组合引擎会使其导入与其他部件提供的内容相符合。

因此,没有必要仔细指定应何时以及如何加载扩展。

例如,可以将许多组件的公用服务分解到单独的部件中,以便于修改或替换。

利用此模型,还可以轻松地开发独立于应用程序的测试工具来测试扩展组件。

通过这种方式,扩展组件本身是自动可扩展的。

可以在客户端应用程序中使用 MEF(无论应用程序使用的是 Windows 窗体、WPF,还是任何其他技术),也可以在使用 ASP.NET 的服务器应用程序中使用 MEF。

这两个框架可以顺利地进行互操作,并且单个应用程序可以同时利用这两个框架。

通过使用 MEF,您将能够在不更改应用程序代码的情况下添加新的运算符。

SimpleCalculator sample(SimpleCalculator 示例)。

注意

Managed Extensibility Framework。

Public 关键字。

CompositionContainer,您可以将此类型用于 SimpleCalculator。

Program 类:

 
private CompositionContainer _container;

应用程序开发人员可以轻松地创建用于从其他源(如 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 类中:

 
[Import(typeof(ICalculator))]
public ICalculator calculator;

此特性将某个对象声明为一个导入;也就是说,在组合对象时将由组合引擎对它进行填充。

MEF 将会自动假定协定基于导入的类型,除非您显式指定协定将基于的类型。)

SimpleCalculator 命名空间中:

 
public interface ICalculator
{
    String Calculate(String input);
}

SimpleCalculator 命名空间中:

 
[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{

}

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 类中:

 
[ImportMany]
IEnumerable<Lazy<IOperation, IOperationData>> operations;

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!”(运算未找到!)消息。

SimpleCalculator 命名空间中:

 
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '-')]
class Subtract : IOperation
{
    public int Operate(int left, int right)
    {
        return left - right;
    }
}

计算器现在支持减法和加法运算。

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 月

添加了指向下载示例的链接。

 

客户反馈

相关文章: