通過前面兩篇文章的介紹,相信各位會明白MEF中有不少實用價值。上一文中我們也讨論了導入與導出,對于導出導入,今天我們再深入一點點,嗯,隻是深入一點點而已,不會很難的,請大家務必放心,如果大家覺得看文章枯燥,不妨一邊喝牛奶一邊閱讀。
上一文中我們都是把整個類型(整個類)進行導出,不過有時候,我們可能會考慮隻導出類的某些成員,比如某個屬性或某個字段等。
我們還是少說理論,免得大家喝不下牛奶,還是直接上菜吧。為了便于測試,以下示例把元件都寫在目前程式集中,也就是在同一個項目,然後用AssemblyCatalog來查找。
首先,定義一個公共接口IWork。
然後分别用兩個類來實作該接口。
接着,我們再定義一個總類,包含兩個屬性,分别傳回FirstWork類和SecondWork類的執行個體。
ExportAttribute特性隻附加在WorkFirst和WorkSecond兩個屬性上,Works類隻導出這兩個屬性。
随後,我們組裝并調用這些導出部件。
然後我們運作一下示例,就可以得到如下圖所示的結果:
很多人學習程式設計很喜歡直接Ctrl + C别人的代碼,這是一種相當不好的學習方法,是以我把代碼都弄成截圖了,哈哈。
我事前在導入字段聲明時用了Lazy<T>,但發現不能建立對象,可能的原因是我們導出的是類的一部分,内部運作時在組裝部件時需要Works類進行執行個體化,因為如果Works對象不執行個體化的話,就導不出WorkFirst和WorkSecond屬性了。也許是這個原因導緻的吧。
這時候大家可能會想,如果我在Works類中定義一個方法,我想導出這個方法怎麼辦?
既然想到了還等什麼,馬上試試就知道了,我們把Works類的代碼改一下,導出一個ViewWork方法。
協定類型為什麼使用Func<TResult>呢?為什麼,大家好好思考一下,用什麼方式來表示方法的簽名與形式最形象?想想吧。
接着我們在Program類中導入這個方法。
導入的協定名與協定類型一定要與導出比對,否則無法導入。這就好比你的言行要比對一樣,否則妹子不會理你。
在完成組裝的代碼後面,我們測試調用導入的方法。
然後運作一下,看看有沒有結果。
不過,最後,還是把完整的代碼貼一下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
namespace MefApp
{
// 作為公共接口
public interface IWork
{
void DoSome();
string WName { get; }
}
// 第一個實作公共接口的類
public class FirstWork : IWork
public void DoSome()
Console.WriteLine("工序一執行。");
public string WName
get { return "工序一"; }
// 第二個實作公共接口的類
public class SecondWork : IWork
Console.WriteLine("工序二執行。");
get { return "工序二"; }
// 隻對成員進行導出的類
public class Works
FirstWork fw;
SecondWork sw;
public Works()
// 初始化
fw = new FirstWork();
sw = new SecondWork();
// 該屬性被導出
[Export("work 1", typeof(IWork))]
public IWork WorkFirst { get {
return fw;
} }
[Export("work 2", typeof(IWork))]
public IWork WorkSecond
get { return sw; }
// 導出方法
[Export("view work", typeof(Func<string>))]
public string ViewWork()
return "本生産線國際一流,由3172個工作單元組成,73265道工序。";
class Program
// 導入
[Import("work 1", typeof(IWork))]
public IWork TheImportFirstWork;
[Import("work 2", typeof(IWork))]
public IWork TheImportSecondWork;
[Import("view work", typeof(Func<string>))]
public Func<string> TheImportViewWorkMethod;
static void Main(string[] args)
// 從目前程式集中發現元件
AssemblyCatalog cat = new AssemblyCatalog(typeof(Program).Assembly);
Program p = new Program();
CompositionContainer container = new CompositionContainer(cat);
container.SatisfyImportsOnce(p);//給合
// 調用測試
if (p.TheImportFirstWork!=null)
Console.Write("類型名:{0} Name:{1} 調用結果:",
p.TheImportFirstWork.GetType().Name,
p.TheImportFirstWork.WName);
p.TheImportFirstWork.DoSome();
if (p.TheImportSecondWork != null)
p.TheImportSecondWork.GetType().Name,
p.TheImportSecondWork.WName);
p.TheImportSecondWork.DoSome();
if (p.TheImportViewWorkMethod != null)
Console.WriteLine(p.TheImportViewWorkMethod());
// 釋容器以及其建立的執行個體
container.Dispose();
Console.Read();
}