MEF 和 Silverlight 的第一个指南(第 I 部分)






4.83/5 (35投票s)
在这篇文章中,我简单介绍了 MEF,然后通过一个控制台应用程序深入讲解了它。请阅读并记得投票和分享您的反馈。
引言
MEF 是一个用于扩展应用程序的框架,它随 .NET Framework 4.0 和 Silverlight 4.0 一同发布。最近我有机会研究了 MEF 与 Silverlight 的结合。我发现它在各种场景中都很有用,因此决定在 Silverlight 中使用 MEF 做点什么。
在这篇文章中,我将首先简单讨论一下 MEF 框架,为您提供一些基本知识,然后将逐步向您展示如何创建一个小的 HelloMEFWorld
控制台应用程序。在下一篇文章中,我将在 Silverlight 应用程序中使用它并展示其特性和功能。请通读全文,如果您需要,请在您的应用程序中使用这个扩展器。不要忘记分享您的反馈和建议,因为这有助于我更详细地改进我的文章,并为您呈现更多内容。
目录
- MEF 简介
- MEF 是如何工作的?
- 为什么要在我们的应用程序中使用 MEF?
- 导出类
- 通过属性导入
- 使用
CompositionContainer
进行组合 - 构建我们的第一个
HelloMEFWorld
应用程序- 项目设置
- 导出契约
- 导入契约
- 设置
CompositionContainer
- 应用程序演示
- 结束语
MEF 简介
MEF,即 Managed Extensibility Framework(托管可扩展性框架),是 .NET Framework 4.0 的一个组件,也增加了对 Silverlight 4.0 的支持。它实际上通过使用扩展来开发封装的代码,而无需任何硬性依赖,从而简化了可扩展应用程序的创建。它的用途类似于 Prism 和/或依赖注入(我更喜欢这样说),因为它为我们提供了开发独立模块的机会。更准确地说,它是一个独立的模块,通过组合来创建功能完备的应用程序。
如果您使用的是 .NET 4.0,则无需为其寻找单独的下载。您需要添加一些随 .NET Runtime 提供的 DLL 的引用。如果您使用的是 .NET 4 之前的版本,您可以在 CodePlex MEF 站点找到包含完整源代码的版本。
如果您想了解其架构,请访问 CodePlex MEF 站点查看 架构概述。
MEF 是如何工作的?
MEF 的核心包含在 Catalog 和 Composition Container 中。Catalog 负责发现应用程序中的扩展,而 Composition Container 负责协调创建和依赖满足。Catalog 允许应用程序使用通过 Export 属性注册的 Export,而 CompositionContainer
则公开方法以获取这些 Export 并在应用程序中使用。
这是一个简单的 MEF 结构图
MEF 中的第一件事是可组合部件(Composable Parts),它提供一个或多个导出(Exports),并依赖于外部服务(如导入(Imports))。可组合部件是一个可组合单元,它实际上由其他可组合部件导出服务和导入。它们通过契约(Contracts)相互依赖,这些契约使用“System.ComponentModel.Composition.Import
”和“System.ComponentModel.Composition.Export
”属性标记为导入或导出。每个导出都有契约,每个导入声明它需要的契约。这些契约是导入和导出之间的桥梁。
组合容器(Composition Container)与目录(Catalog)交互以访问可组合部件,目录返回的部件是您的应用程序所需的扩展。基于导入和导出,组合容器将其加载到应用程序单元中。
为什么要在我们的应用程序中使用 MEF?
MEF 解决了应用程序中两个模块之间的依赖关系,也解决了运行时可扩展性问题。扩展的实现和工作性质可以被各种应用程序或单个应用程序重用。它们可能相互依赖,但 MEF 会负责它们的加载顺序。因此,如果您需要为应用程序提供运行时可扩展性支持,您可以非常轻松地使用此框架,并为您的客户提供具有插件支持的应用程序。
当您想按需从特定位置加载程序集时,这有时会很有帮助。我稍后会向您展示如何做到这一点。
Visual Studio 2010 支持 MEF,您可以使用 MEF 可扩展性来扩展应用程序。更多内容可以在 CodePlex MEF 站点找到。阅读更多相关内容,并在您的下一个应用程序中实现同样的功能。
现在,让我们更详细地讨论每个主题,以实现一个 MEF 应用程序。我们将从概念开始,然后创建一个小型应用程序。
导出类
导出类非常简单。您只需用名为“System.ComponentModel.Composition.Export
”的属性标记您的契约即可。完成后,您的契约类将由 MEF 自动导出以供导入。让我们看看如何做到这一点
[Export(typeof(IPerson))]
public class Employee : IPerson
{
}
通过属性导入
这类似于依赖注入。您必须使用“System.ComponentModel.Composition.Import
”属性标记您的同类型属性。这将在您的组合容器中为该属性导入一个类型的单个实例。让我们看看代码
public class Program
{
[Import]
public IPerson Persons { get; set; }
}
如果您想导入导出类型的集合,您需要将“System.ComponentModel.Composition.ImportMany
”属性设置为该属性,并且该属性应该声明为 Collection。让我们看看代码
public class Program
{
[ImportMany]
public IPerson[] Persons { get; set; }
}
使用 CompositionContainer 进行组合
CompositionContaner
构建所有部件并初始化它们以供使用。首先,您需要创建目录,然后您必须从 composition
容器组合部件。有四种类型的 Catalog
可用:“AggregateCatalog
”、“AssemblyCatalog
”、“DirectoryCatalog
”和“TypeCatalog
”。AggregateCatalog
包含 ComposablePartCatalog
对象的可变集合。AssemblyCatalog
包含从托管代码程序集创建的不可变 ComposablePartCatalog
对象。DirectoryCatalog
表示从 Directory
路径内容中的 ComposablePartCatalog
对象。TypeCatalog
是 ComposablePartCatalog
的不可变对象,它是从 Type 数组或托管类型列表创建的。
让我们看一些示例代码。首先,我们将从执行程序集创建目录,下一步我们将从目录位置创建它。
private void CreateCompositionContainerFromAssembly()
{
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer compositionContainer = new CompositionContainer(catalog);
compositionContainer.ComposeParts(this);
}
private void CreateCompositionContainerFromDirectory()
{
DirectoryCatalog catalog = new DirectoryCatalog(@".\");
CompositionContainer compositionContainer = new CompositionContainer(catalog);
compositionContainer.ComposeParts(this);
}
构建我们的第一个 HelloMEFWorld 应用程序
现在我们对 MEF 有了一些基本概念。让我们尝试实现一个小型应用程序。它将给我们更多的知识。我们将把它分解成一些小块,并一步一步地完成。
为了开发我们的第一个 MEF 应用程序,我们需要在开始之前设置好以下开发环境
- Visual Studio 2010 IDE(包含 .NET 4.0)
一旦我们的开发环境准备就绪,我们就可以跳到下一步创建项目。
项目设置
在本文中,我将创建一个控制台应用程序。在下一篇文章中,我将为 Silverlight 描述它。因此,打开您的 Visual Studio 2010 并创建一个控制台应用程序。请确保在创建项目时选择了 .NET 4.0 框架。
IDE 创建项目后,您需要向项目中添加名为“System.ComponentModel.Composition
”的程序集引用。为此,右键单击您的控制台应用程序项目并单击“添加引用”。
从“添加引用”对话框中,找到名为“System.ComponentModel.Composition
”的程序集并将其添加到您的项目中。
现在您的项目已准备好进行 MEF 开发。让我们创建具有必要接口和类的基本项目结构。这将在稍后进行 MEF 集成时对我们有所帮助。
首先,我们将开始设计我们的接口,名为“IPerson
”,其中包含一个方法调用 WriteMessage()
。代码如下
namespace HelloMEFWorld
{
public interface IPerson
{
void WriteMessage();
}
}
现在是时候实现接口了。我们将创建两个名为“Customer
”和“Employee
”的类,它们都继承自接口 IPerson
。我们必须实现接口方法。让我们用一些适当的消息写入 Console
来完成它
namespace HelloMEFWorld
{
public class Customer : IPerson
{
public void WriteMessage()
{
Console.WriteLine("I am your Customer");
Console.ReadLine();
}
}
}
namespace HelloMEFWorld
{
public class Employee : IPerson
{
public void WriteMessage()
{
Console.WriteLine("I am your Employee");
Console.ReadLine();
}
}
}
导出契约
现在是导出契约的时候了,这样我们就可以在应用程序中使用它。为此,我们应该怎么做?没错,您是对的。我们必须使用 Export
属性将 contact
类标记为 Exportable
。现在,我们只对 Customer
类进行此操作。因此,打开您的 Customer
类,并将其属性设置为 IPerson
类型的 Export
。这是代码
using System;
using System.ComponentModel.Composition;
namespace HelloMEFWorld
{
[Export(typeof(IPerson))]
public class Customer : IPerson
{
public void WriteMessage()
{
Console.WriteLine("I am your Customer");
Console.ReadLine();
}
}
}
您的“Customer
”类已准备好进行 Export
。现在我们需要在“Program
”类中导入它。
导入契约
要导入一个 contract
,我们需要创建一个属性。我之前在顶部描述时已经提到了。让我们创建 IPerson
类型的属性。我们将使用这种类型,以便我们可以导入 Customer
和 Employee
。因此,打开 Program.cs 文件,并创建一个名为“Persons
”、类型为 IPerson
数组的属性。将该属性的属性设置为 ImportMany
。如果您想为 IPerson
的单个实例执行此操作,请使用 IPerson
类型的属性并将其标记为“Import
”。在我们的示例中,我们使用 IPerson[]
,因此标记为 ImportMany
。
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
namespace HelloMEFWorld
{
public class Program
{
[ImportMany]
public IPerson[] Persons { get; set; }
static void Main(string[] args)
{
}
}
}
现在我们将创建一个方法,该方法将遍历集合并调用 IPerson
的 WriteMessage()
方法。然后我们将在 Person
类的 Main
方法中调用它。完整代码如下所示
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
namespace HelloMEFWorld
{
public class Program
{
[ImportMany]
public IPerson[] Persons { get; set; }
static void Main(string[] args)
{
Program p = new Program();
p.ListAllPersons();
}
private void ListAllPersons()
{
foreach (var person in Persons)
{
person.WriteMessage();
}
}
}
}
如果您运行应用程序,我们将得到 NullReferenceException
,因为 Persons
集合是 null
。所以,让我们填充集合。怎么做呢?阅读下一段。
使用 CompositionContainer 进行组合
填充集合很容易,对吧?您需要创建一个 Customer
类的实例并将其添加到集合中。我是对的吗?等等,这在 MEF 中是错误的。如果您想这样填充它,那么 MEF 的必要性何在?MEF 允许您在应用程序开发中不直接依赖于模块。那么该怎么做呢?我们必须首先创建目录,然后从 CompositionContainer
组合部件,如前所述。让我们创建一个不同的方法来完成同样的事情。
private void CreateCompositionContainer()
{
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
CompositionContainer compositionContainer = new CompositionContainer(catalog);
compositionContainer.ComposeParts(this);
}
现在从 ListAllPersons()
方法调用 CreateCompositionContainer()
方法。在遍历集合之前,在第一行执行此操作。这将用导出的契约初始化集合属性。
应用程序演示
由于我们的组合容器已准备就绪,运行应用程序,您现在将不会遇到任何异常。您将看到 Customer
类的 WriteMessage()
已自动调用,并将消息“I am your Customer
”写入屏幕。
我们没有编写任何特定的代码来创建 Customer
类的实例。它由 MEF 自动完成。在组合 Container
时,它会将实例加载到属性中。现在我们将 Employee
类添加到这里。为此,只需将 Export 属性添加到 contract
类。这与我们为 Customer
类所做的相同。但为了您的参考,代码如下
using System;
using System.ComponentModel.Composition;
namespace HelloMEFWorld
{
[Export(typeof(IPerson))]
public class Employee : IPerson
{
public void WriteMessage()
{
Console.WriteLine("I am your Employee");
Console.ReadLine();
}
}
}
再次运行您的应用程序。哇噢!!!它也创建了 Employee
类!无需为集成 Employee
类编写任何额外的代码。这就是 MEF。它为您的应用程序提供了平滑的可扩展性,而无需修改原始代码。如果您了解它的类型,那就行了。它会完成这些事情。这是输出的快照
那么,内部发生了什么?如果您调试代码,您会注意到目录有两个部分:“Customer
”和“Employee
”。
此外,它还填充了集合属性。就是这样
结束语
那么,现在呢?希望您对 MEF 框架有了基本的了解,也对我们可以使用 MEF 做些什么有了概念。因此,探索它并在您的项目中按需使用。在我的下一篇文章中,我将向您展示如何在 Silverlight 应用程序中使用它。在此之前,请享受阅读我的文章并使用 MEF 的乐趣。
如果您有任何反馈或建议,请随时在此分享。我始终感谢您花时间阅读我的文章并分享您的反馈。
请为本文 投票。
历史
- 2010年8月15日:首次发布