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的类型,从而区分导入的类型。

 

点击这里,下载源码

 

MEF系列文章:

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

C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)

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

C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

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

 

转载于:https://www.cnblogs.com/yunfeifei/p/3991330.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
0 大家都知道 XAML是“用来设计UI”的 设计师用XAML设计出来的UI其后台代码(程序逻辑)可以由程序员用C#或者VB去写 这叫做Code behind 实际上 设计师用XAML和程序用C#都是在构建同一个类 换句话说就是:把一个类劈成两半 与UI相关的那半由设计师用XAML写 与逻辑相关的那半由程序员用C#写 1 这个Name属性是非常重要的 如果你想在一棵“树”上查找叫某个名字的元素 调用“树根”的FindName方法就可以做到了 3 TextBox t this FindName "Made in China" as TextBox; 4 x:Name的x加一个冒号 说明它来自x这个名称空间 这个名称空间是定义在XAML的根元素上的 也就是这句: xmlns:x [url]http: schemas microsoft com winfx 2006 xaml[ url] 这个x就是XAML的字头了 这个名称空间的本意就是告诉我们 这个名称空间里所装的元素都与XAML解析有关 比如 我在代码里还使用了x:Code 把本来应该呆在C#代码里的内容请到XAML里来了 5 <Window x:Class < 只使用xaml编写一个窗体 >< 只使用一个单独的xaml文件 > namespace Cnblog{ 只使用Code Behind编写一个窗体 只使用一个单独的OnlyCo 6 XAML中x:Name和Name最终效果相同 XAML中使用Name其实被映射到了x:Name x:Name才是XAML中唯一的标识 所以它们效果相同 x:Name不是SomeWpfType Name 当我们设置了x:Name后(假设为ElementName XAML中x:Name与Name并不完全等价 不是所有类型都可以使用Name 但是任何类型都可以使用x:Name 只有拥有Name属性 才可以在XAML中使用Name 不同于x:Name 因为这个是附加属性 并且该类型 或者其父类型标记了RuntimeNameProperty特性 才拥有与x:Name一样的效果 例如:<SolidColorBrush Color "Transparent" Name "ddd" >便会报错 因为SolidColorBrush没有Name属性 只能使用x:Name <SolidColorBrush Color "Transparent" x:Name "ddd" > 1 分析为什么要有x:Name">0 大家都知道 XAML是“用来设计UI”的 设计师用XAML设计出来的UI其后台代码(程序逻辑)可以由程序员用C#或者VB去写 这叫做Code behind 实际上 设计师用XAML和程序用C#都是在构建同一个类 换句话说就是:把一个类劈成 [更多]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值