C#可擴展編程之MEF學習筆記(二):MEF的導出(Export)和導入(Import)


  上一篇學習完了MEF的基礎知識,編寫了一個簡單的DEMO,接下來接着上篇的內容繼續學習,如果沒有看過上一篇的內容,

請閱讀:http://www.cnblogs.com/yunfeifei/p/3922668.html。

  下面我們來主要講解一下MEF中的導入和導出,還是上一篇的代碼(這篇中,我還會貼出完整的代碼),修改Program的代碼如下:

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

namespace MEFDemo
{
   class Program
   {
      [Import("MusicBook")]
      public IBookService Service { get; set; }

      static void Main(string[] args)
      {
         Program pro = new Program();
         pro.Compose();
         if (pro.Service != null)
         {
            Console.WriteLine(pro.Service.GetBookName());
         }
         Console.Read();
      }

      private void Compose()
      {
         var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
         CompositionContainer container = new CompositionContainer(catalog);
         container.ComposeParts(this);
      }
   }
}

修改MusicBook的代碼如下:

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

namespace MEFDemo
{
   [Export("MusicBook",typeof(IBookService))]
   public class MusicBook : IBookService
   {
      public string BookName { get; set; }

      public string GetBookName()
      {
         return "MusicBook";
      }
   }
}

注意,標紅的是改動過的地方,其他地方的代碼沒有變,上一次我們使用的是Export的方法是[Export(typeof(IBookService))],這次前面多了一個參數,沒錯,這個就是一個契約名,名字可以隨便起,而且可以重復,但是如果名字亂起,和其他DLL中的重復,到時候會導致程序出現很多Bug,最好按照一定的規范去起名字。

這里有了契約名以后,導入(Import)時就要指定的契約名,否則將無法找到MusicBook,Export還有一個方法是[Export("Name")],這個方法只指定了契約名,沒有指定導出類型,那么默認的導出類型是object類型,在導入時導出到的對象就要為object類型,否則將匹配不到那個組件。

  到現在,我們只寫了一個接口和一個實現類,導出的也是一個類,下面我們多添加幾個類來看看會怎么樣,為了方便大家測試,我把實現接口的類寫在一個文件里面,新加幾個類后,的MusicBook類文件代碼如下:

 

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

namespace MEFDemo
{
   [Export("MusicBook",typeof(IBookService))]
   public class MusicBook : IBookService
   {
      public string BookName { get; set; }

      public string GetBookName()
      {
         return "MusicBook";
      }
   }

   [Export("MusicBook", typeof(IBookService))]
   public class MathBook : IBookService
   {
      public string BookName { get; set; }

      public string GetBookName()
      {
         return "MathBook";
      }
   }

   [Export("MusicBook", typeof(IBookService))]
   public class HistoryBook : IBookService
   {
      public string BookName { get; set; }

      public string GetBookName()
      {
         return "HistoryBook";
      }
   }

}

 

這里添加兩個類,HistoryBook和MathBook,都繼承自IBookService接口,注意他們的契約名都相同,都為MusicBook,后面再詳細的說這個問題,修改后的program的代碼如下:

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

namespace MEFDemo
{
   class Program
   {
      [ImportMany("MusicBook")]
      public IEnumerable<IBookService> Services { get; set; }

      static void Main(string[] args)
      {
         Program pro = new Program();
         pro.Compose();
         if (pro.Services != null)
         {
            foreach (var s in pro.Services)
            {
               Console.WriteLine(s.GetBookName());
            }
         }
         Console.Read();
      }

      private void Compose()
      {
         var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
         CompositionContainer container = new CompositionContainer(catalog);
         container.ComposeParts(this);
      }
   }
}

這里需要注意的是標紅的兩行代碼,[ImportMany("MusicBook")]還有下面的聲明變成了IEnumerable<>,因為要導出多個實例,所以要用到集合,下面采用foreach遍歷輸出,運行的結果如下圖:

 

一共三個,都輸出了,對吧!是不是很好用啊,哈哈~~

當然,如果想全部輸出,可以向第一篇文章中那樣,導入和導出時都不寫契約名,就會全部導出。那么寫契約名有什么好處呢?

下面我們用代碼說明問題,修改實現類的契約名如下:

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

namespace MEFDemo
{
   [Export("MusicBook",typeof(IBookService))]
   public class MusicBook : IBookService
   {
      public string BookName { get; set; }

      public string GetBookName()
      {
         return "MusicBook";
      }
   }

   [Export("MathBook", typeof(IBookService))]
   public class MathBook : IBookService
   {
      public string BookName { get; set; }

      public string GetBookName()
      {
         return "MathBook";
      }
   }

   [Export("HistoryBook", typeof(IBookService))]
   public class HistoryBook : IBookService
   {
      public string BookName { get; set; }

      public string GetBookName()
      {
         return "HistoryBook";
      }
   }

}

現在三個類的契約名都不相同了,其他的代碼不動,再次運行程序看看,是不是現在只輸出MusicBook了,同理,修改[Import("Name")]中的契約名稱,就會導入指定含有名稱的類,契約名可以重復,這一以來,我們就可以用契約名給類進行分類,導入時可以根據契約名來導入。

注意IEnumerable<T>中的類型必須和類的導出類型匹配,如類上面標注的是[Exprot(typeof(object))],那么就必須聲明為IEnumerable<object>才能匹配到導出的類。

例如:我們在類上面標注[Export("Book")],我們僅僅指定了契約名,而沒有指定類型,那么默認為object,此時還用IEnumerable<IBookService>就匹配不到。

那么,這種情況就要在輸出是進行強制類型轉換,代碼如下:

[Export("MusicBook")]
   public class MusicBook : IBookService
   {
      public string BookName { get; set; }

      public string GetBookName()
      {
         return "MusicBook";
      }
   }

program中的代碼改變如下:

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

namespace MEFDemo
{
   class Program
   {
      [ImportMany("MusicBook")]
      public IEnumerable<object> Services { get; set; }

      static void Main(string[] args)
      {
         Program pro = new Program();
         pro.Compose();
         if (pro.Services != null)
         {
            foreach (var s in pro.Services)
            {
               var ss = (IBookService)s; Console.WriteLine(ss.GetBookName());
            }
         }
         Console.Read();
      }

      private void Compose()
      {
         var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
         CompositionContainer container = new CompositionContainer(catalog);
         container.ComposeParts(this);
      }
   }
}

這樣就可以正常運行了~~

點擊這里下載源碼

 

MEF系列文章:

 C#可擴展編程之MEF學習筆記(一):MEF簡介及簡單的Demo

C#可擴展編程之MEF學習筆記(二):MEF的導出(Export)和導入(Import)

C#可擴展編程之MEF學習筆記(三):導出類的方法和屬性

C#可擴展編程之MEF學習筆記(四):見證奇跡的時刻

C#可擴展編程之MEF學習筆記(五):MEF高級進階

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM