C#可擴充套件程式設計之MEF學習筆記(五):MEF高階進階

雲霏霏發表於2014-09-24

好久沒有寫部落格了,今天抽空繼續寫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高階進階

 

相關文章