C#可扩展编程之MEF学习笔记(五):MEF高级进阶(转)

好久没有写博客了,今天抽空继续写MEF系列的文章。有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后。

前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用的基本已经讲完了,相信大家已经能看出MEF所带来的便利了。今天就介绍一些MEF中一些较为不常用的东西,也就是大家口中的所谓的比较高级的用法。

前面讲的导出都是在每个类上面添加Export注解,实现导出的,那么有没有一种比较简便的方法呢?答案是有的,就是在接口上面写注解,这样只要实现了这个接口的类都会导出,而不需要在每个类上面都写注解。下面仅贴出接口和一个实现类的源码,其余的模仿即可:

接口代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;

namespace BankInterface
{
   [InheritedExport]
   public interface ICard
   {
      //账户金额
      double Money { get; set; }
      //获取账户信息
      string GetCountInfo();
      //存钱
      void SaveMoney(double money);
      //取钱
      void CheckOutMoney(double money);
   }

}

接口上面添加了[InheritedExport]标记,没错,这个就是用在接口上面的注解。

下面给出一个实现类的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BankInterface;
using System.ComponentModel.Composition;

namespace BankOfChina
{
   //[Export(typeof(ICard))]
   public class ZHCard : ICard
   {
      public string GetCountInfo()
      {
         return "Bank Of China";
      }

      public void SaveMoney(double money)
      {
         this.Money += money;
      }

      public void CheckOutMoney(double money)
      {
         this.Money -= money;
      }

      public double Money { get; set; }
   }
}

可以看到,我注释掉了导出的注解,运行后,依然可以看到,此类还是被导出了,运行结果相信看过上一篇的都已经知道了。

注意:这种方法虽然比较简单,但是只适用于比较简单的应用,看完下面后,相信大家会意识到他的不足。

下面进入今天的重点:

 MEF中如何访问某个具体的对象                                                                      

  前面我们讲过在导出的时候,可以在[Export()]注解中加入名称标识,从而识别某个具体的对象,然而这种方法只是用于页面初始化的时候就行过滤,页面打开后没有导入的就再也导入不了了,就是说我们不能在导入的集合中分辨各自的不同,所有导入的类都是没有标识的。

  为了给每一个类添加标识,我们要继承ExportAttribute类,为他添加标识属性MetaData,首先来写继承自ExportAttribute的类,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;

namespace BankInterface
{
   /// <summary>
   /// AllowMultiple = false,代表一个类不允许多次使用此属性
   /// </summary>
   [MetadataAttribute]
   [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
   public class ExportCardAttribute : ExportAttribute
   {
      public ExportCardAttribute()
         :base(typeof(ICard))
      {
      }

      public string CardType { get; set; }
   }
}

代码很简单,调用的父类的构造方法,声明了一个属性CatdType,下面来添加一个接口,直接修改ICard接口文件,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;

namespace BankInterface
{
   public interface ICard
   {
      //账户金额
      double Money { get; set; }
      //获取账户信息
      string GetCountInfo();
      //存钱
      void SaveMoney(double money);
      //取钱
      void CheckOutMoney(double money);
   }

   public interface IMetaData
   {
      string CardType { get;}
   }
}

又添加了接口IMetaData,只有一个属性,注意这个属性要和刚写的ExportCardAttribute类中的属性名称要一致,这样才能实现导出。

下面利用我们的ExportCardAttribute属性来标记我们要导出的类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BankInterface;
using System.ComponentModel.Composition;

namespace BankOfChina
{
   [ExportCardAttribute(CardType="BankOfChina")]
   public class ZHCard : ICard
   {
      public string GetCountInfo()
      {
         return "Bank Of China";
      }

      public void SaveMoney(double money)
      {
         this.Money += money;
      }

      public void CheckOutMoney(double money)
      {
         this.Money -= money;
      }

      public double Money { get; set; }
   }
}

在这里,我们可以设置CardType的属性,可以根据具体情况使用不同的数据类型。

现在,我们修改主程序的代码为:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using BankInterface;

namespace MEFDemo
{
   class Program
   {
      //其中AllowRecomposition=true参数就表示运行在有新的部件被装配成功后进行部件集的重组.
      [ImportMany(AllowRecomposition = true)]
      public IEnumerable<Lazy<ICard,IMetaData>> cards { get; set; }

      static void Main(string[] args)
      {
         Program pro = new Program();
         pro.Compose();
         foreach (var c in pro.cards)
         {
            if (c.Metadata.CardType == "BankOfChina")
            {
               Console.WriteLine("Here is a card of Bank Of China ");
               Console.WriteLine(c.Value.GetCountInfo());
            }
            if (c.Metadata.CardType == "NongHang")
            {
               Console.WriteLine("Here is a card of Nong Ye Yin Hang ");
               Console.WriteLine(c.Value.GetCountInfo());
            }
         }
         Console.Read();
      }

      private void Compose()
      {
         var catalog = new DirectoryCatalog("Cards");
         var container = new CompositionContainer(catalog);
         container.ComposeParts(this);
      }
   }
}

这里我用到了Lazy延迟加载机制(具体参见Lazy延迟加载),可以看到我们可以根据MetaData的属性访问到CardType属性,从而判断出Card的类型,从而区分导入的类型。

点击这里,下载源码

时间: 2024-08-04 22:45:39

C#可扩展编程之MEF学习笔记(五):MEF高级进阶(转)的相关文章

C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo

在文章开始之前,首先简单介绍一下什么是MEF,MEF,全称Managed Extensibility Framework(托管可扩展框架).单从名字我们不难发现:MEF是专门致力于解决扩展性问题的框架,MSDN中对MEF有这样一段说明: Managed Extensibility Framework 或 MEF 是一个用于创建可扩展的轻型应用程序的库. 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置. 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项. 通过 MEF,不

C#可扩展编程之MEF学习笔记(三):导出类的方法和属性

前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供了下载链接,大家可以下载学习. 首先来说导出属性,因为这个比较简单,和导出类差不多,先来看看代码,主要看我加注释的地方,MusicBook.cs中的代码如下: using System; using System.Collections.Generic; using System.Linq; usi

Caliburn.Micro学习笔记(五)----协同IResult

Caliburn.Micro学习笔记(五)----协同IResult 今天说一下协同IResult 看一下IResult接口 /// <summary> /// Allows custom code to execute after the return of a action. /// </summary> public interface IResult { /// <summary> /// Executes the result using the specif

java之jvm学习笔记五(实践写自己的类装载器)

java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类装载器和安全管理器是可以被动态扩展的,或者说,他们是可以由用户自己定制的,今天我们就是动手试试,怎么做这部分的实践,当然,在阅读本篇之前,至少要阅读过笔记三. 下面我们先来动态扩展一个类装载器,当然这只是一个比较小的demo,旨在让大家有个比较形象的概念. 第一步,首先定义自己的类装载器,从Clas

WEB前端学习笔记 五

接web前端学习笔记第四篇,此篇为web学习笔记 五,在此感谢您的采集和转发,但请注明文章出自网知博学. 2.0.3  html标签的属性格式 现在我们知道了两个双标签分别是,标题标签:<h1> - <h6>.和段落标签:<p></p>还知道了一个换行的单标签:<br />,现在我们给<p></p>标签添加一个属性,来改变段落是右对齐,还是左对齐,还是居中. 如上图,<p>标签中的 align(中文就是排列的意

angular学习笔记(五)-阶乘计算实例(1)

<!DOCTYPE html> <html ng-app> <head> <title>2.3.2计算阶乘实例1</title> <meta charset="utf-8"> <script src="../angular.js"></script> <script src="script.js"></script> </

NLTK学习笔记(五):分类和标注词汇

[TOC] 词性标注器 之后的很多工作都需要标注完的词汇.nltk自带英文标注器pos_tag import nltk text = nltk.word_tokenize("And now for something compleyely difference") print(text) print(nltk.pos_tag(text)) 标注语料库 表示已经标注的标识符:nltk.tag.str2tuple('word/类型') text = "The/AT grand/J

Linux System Programming 学习笔记(五) 进程管理

1. 进程是unix系统中两个最重要的基础抽象之一(另一个是文件) A process is a running program A thread is the unit of activity inside of a process the virtualization of memory is associated with the process, the threads all share the same memory address space 2. pid The idle pro

小猪的数据结构学习笔记(五)

小猪的数据结构学习笔记(五) 线性表之--循环链表                           --转载请注明出处:coder-pig 循环链表知识点归纳: 相关代码实现: ①判断是否为空表: ②单循环链表的存储结构 其实和单链表的结构是一样的! /*定义循环链表的存储结构*/ typedef struct Cir_List { int data; struct Cir_List *next; }Lnode; ③初始化循环单链表 代码如下: //1.循环链表的初始化 //表示一个元素,如