65.9K
CodeProject 正在变化。 阅读更多。
Home

高级MEF编程

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.80/5 (5投票s)

2011 年 2 月 6 日

CPOL

4分钟阅读

viewsIcon

34813

高级MEF编程

导入类型

.NET 4.0 引入了许多新的编程概念,MEF 支持其中的一些。MEF 支持几种导入类型,包括动态、延迟、必备和可选。

随附的源代码包含了一些我在本博客中未讨论的高级 MEF 编程概念。您可以逐行调试源代码并探索这些概念。

动态导入

.NET 4.0 引入了一个新类型,即 `dynamic`。该类型是 `static` 类型,但 `dynamic` 类型的对象会绕过 `static` 类型检查。在大多数情况下,它的功能类似于 `type` 对象。在编译时,类型为 `dynamic` 的元素被假定支持任何操作。因此,您不必担心对象是从 COM API、动态语言(如 IronPython)、HTML 文档对象模型 (DOM)、反射还是程序中的其他位置获取其值的。但是,如果代码无效,则会在运行时捕获错误。

在某些情况下,导入类可能希望匹配具有特定约定名称的任何类型的导出。在这种情况下,该类可以声明一个动态导入。以下导入匹配具有约定名称“DemoOfDynamicImport”的任何导出。

  1  [Import("DemoOfDynamicImport")]
  2  public dynamic somedynamicclassobject;

当约定类型从 `dynamic` 关键字推断出来时,它将匹配任何约定类型。在这种情况下,导入**始终**应指定一个要匹配的约定名称。(如果未指定约定名称,则导入将被视为不匹配任何导出。)以下两个导出都会匹配前面的导入。导入类必须准备好处理任意类型的对象。

  1  [Export("DemoOfDynamicImport", typeof(IGreeting))]
  2  public class DemoOfDynamicImportClass
  3  {
  4      public string SayHelloWorld()
  5      {
  6          return "Hello from DemoOfDynamicImport Class";
  7      }
  8  }
延迟导入

在某些情况下,导入类可能需要对导入对象的间接引用,以便不立即实例化该对象。在这种情况下,该类可以通过使用 `Lazy` 的约定类型来声明延迟导入。以下导入属性声明了一个延迟导入。为了解释多个概念,我使用了不同的技术创建了不同的对象。请随意使用其中任何一个。

  1  [Import("IMyLazyClass",AllowDefault = true)]
  2  public Lazy<MyLazyClass> objlazyclass;
  3   
  4  [ImportMany]
  5  public Lazy<IGreeting>[] Greetings1 { get; set; }
  6   
  7  [ImportMany]
  8  public IEnumerable<Lazy<IGreeting>> Greetings2 { get; set; }

从组合引擎的角度来看,`Lazy` 的约定类型被认为与 `T` 的约定类型相同。因此,前面的导入将匹配以下导出。以下 `Export` 匹配上面代码第 1 行的 `Import`。

  1  [Export("IMyLazyClass")]
  2  class MyLazyClass
  3  {
  4      public string SayHelloWorld()
  5      {
  6          return "Hello from MyLazyClass";
  7      }
  8  }

以下 `Export` 代码匹配上面 `Import` 代码的第 4 行或第 7 行的 `Import`。可以在 `Import` 属性中为延迟 `import` 指定约定名称和约定类型。

  1  [Export(typeof(IGreeting))]
  2  public class SimpleGreetingClass : IGreeting
  3  {
  4      public string SayHelloWorld()
  5      {
  6          return "Hello World !!!";
  7      }
  8   
  9      //Explicitly specifying a generic type.
 10      [Export(typeof(Func<int, string>))]
 11      public string DoSomething(int TheParam)
 12      {
 13          return "From Func: You Entered " + TheParam.ToString();
 14      }
 15  }

可选导入

Import 属性指定了部件正常运行的要求。如果导入无法满足,该部件的组合将失败,该部件将不可用。您可以使用 `AllowDefault` 属性指定 `import` 是可选的。在这种情况下,即使 `import` 未匹配任何可用导出,组合也会成功,并且导入属性将被设置为其属性类型的默认值(对象属性为 `null`,布尔值为 `false`,数字属性为零)。以下类使用了一个可选导入。

  1  [Import("IMyLazyClass", AllowDefault = true)]
  2  public Lazy<MyLazyClass> objlazyclass; 

元数据

Export 可以提供有关它们自身的额外信息,称为元数据。元数据可用于将导出对象属性传达给导入部件。导入部件可以使用这些数据来决定使用哪些 `export`,或在不构造 `export` 的情况下收集有关 `export` 的信息。因此,`import` 必须是延迟的才能使用元数据。要使用元数据,通常会声明一个称为元数据视图的接口,该接口声明将提供哪些元数据。元数据视图接口只能包含属性,并且这些属性必须具有 get 访问器。为了允许访问元数据,MEF 利用了 .NET Framework 4 的一个新 API `System.Lazy`。它允许将实例的实例化推迟到访问 `Lazy` 的 `value` 属性。MEF 进一步扩展了 `Lazy`,使其成为 `Lazy`,以允许在不实例化基础导出 (export) 的情况下访问导出元数据。`TMetadata` 是一个元数据视图类型。元数据视图是一个接口,它定义了与导出元数据中的键对应的只读属性。当访问元数据属性时,MEF 将动态实现 `TMetadata`,并根据从导出中提供的元数据设置值。

以下类是元数据的示例。请参见第 25 行。

  1  using System;
  2  using System.ComponentModel.Composition;
  3  using ContractsLibrary;
  4   
  5  namespace MEFPart1
  6  {
  7      [Export(typeof(IGreeting))]
  8      public class SimpleGreetingClass : IGreeting
  9      {
 10          public string SayHelloWorld()
 11          {
 12              return "Hello World !!!";
 13          }
 14   
 15          //Explicitly specifying a generic type.
 16          [Export(typeof(Func<int, string>))]
 17          public string DoSomething(int TheParam)
 18          {
 19              return "From Func: You Entered " + TheParam.ToString();
 20          }
 21      }
 22   
 23   
 24      [Export(typeof(IGreeting))]
 25      [ExportMetadata("Name", "Kishore")]
 26      public class SimpleMetaDataClass : IGreeting
 27      {
 28          public string SayHelloWorld()
 29          {
 30              return "Hello World from SimpleMetaDataClass. 
		Checking the metadata name at runtime !!!";
 31          }
 32      } 
 33  }

以下类是元数据的示例。请参见第 11 行。

  1  using System;
  2  using System.Collections.Generic;
  3  using System.Linq;
  4  using System.Text;
  5  using System.ComponentModel.Composition;
  6  using ContractsLibrary;
  7   
  8  namespace MEFPart2
  9  {
 10      [Export(typeof(IGreeting))]
 11      [ExportMetadata("Name", "Babu")]
 12      public class ExtendedGreeting : IGreeting
 13      {
 14          public string SayHelloWorld()
 15          {
 16              return "Hello " + Environment.UserDomainName + "\\" + 
						Environment.UserName;
 17          }
 18      }
 19   
 20      //[PartNotDiscoverable]
 21      // A part decorated with PartNotDiscoverabl attribute 
         // will not be included in any catalogs. 
 22      //So in the main exe, you will get runtime composition error
 23      [Export("DemoOfDynamicImport", typeof(IGreeting))]
 24      public class DemoOfDynamicImportClass
 25      {
 26          public string SayHelloWorld()
 27          {
 28              return "Hello from DemoOfDynamicImport Class";
 29          }
 30      }
 31  }

带有元数据的 `import` 被声明为一个延迟导入,并将元数据接口作为 `Lazy` 的第二个类型参数。以下类导入了带有元数据的上一个部件。

  1  [ImportMany]
  2  public IEnumerable<Lazy<IGreeting, IGreetingMetadata>> greetingmetadata 

一旦导入了带有元数据的延迟导出集合,就可以使用 LINQ(已注释掉)对其进行过滤,如以下代码片段所示。

  1  foreach (Lazy<IGreeting, IGreetingMetadata> 
		greetingmeta in greetingmetadataobjects)
  2  {
  3      if (greetingmeta.Metadata.Name == "Kishore")
  4      {
  5          Console.WriteLine(greetingmeta.Value.SayHelloWorld());
  6          //or we can create an object depending on the metadata value at runtime
  7          IGreeting objgreeting = greetingmeta.Value;
  8          Console.WriteLine(objgreeting.SayHelloWorld());
  9      }
 10  }
 11   
 12  ////The below commented code also performs the same task as the following code.
 13  ////Following is the code incase, you want to create an object of a class using LINQ
 14  //IEnumerable<IGreeting> objgreeting = greetingmetadataobjects.Where
		(v => v.Metadata.Name.Equals("Kishore")).Select(v => v.Value);
 15  //foreach (var greeting in objgreeting)
 16  //{
 17  //    if (greeting != null)
 18  //    {
 19  //        Console.WriteLine(greeting.SayHelloWorld());
 20  //    }
 21  //}
源代码可在以下位置找到:

Microsoft: http://cid-38ecce05b21b8b44.office.live.com/self.aspx/MY%20Projects/All%20MEF%20Concepts.zip

“不要走别人走过的路,而是去没有路的地方,并留下你的足迹。”


分类: 高级 MEF 概念, CodeProject, MEF
© . All rights reserved.