基于MEF打造的插件系統(tǒng)的實現(xiàn)詳解
以實例說話,一起體驗MEF帶來的可擴展性吧,Let's Rock?。。?/FONT>
1:新建控制臺程序SimpleCalculator
在這里要實現(xiàn)的程序時SimpleCalculator,顧名思義:簡單的計算器。
所以我們需要定義一個用來計算的接口:
public interface ICalculator
{
String Calculate(String input);
}
Program 的代碼如下:
class Program
{
private CompositionContainer _container;
[Import(typeof(ICalculator))]
private ICalculator calculator;
public Program()
{
//var catalog = new AggregateCatalog();
//catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
_container = new CompositionContainer(catalog);
try
{
this._container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
static void Main(string[] args)
{
Program p = new Program();
string s;
Console.WriteLine("Enter Command:");
while (true)
{
s = Console.ReadLine();
Console.WriteLine(p.calculator.Calculate(s));
}
}
}
MEF所要解決的是尋找插件的功能,傳統(tǒng)的實現(xiàn)插件的方式主要是使用接口,即聲明一個接口,然后使用配置文件來配置接口使用哪個實現(xiàn)類。
微軟知道有這種需求,于是提供了MEF來實現(xiàn)插件的功能。
Composite 原理:
1:聲明一個 CompositionContainer 對象,這個對象里面包含一堆Catalog.
2:這堆Catalog如果是AssemblyCatalog,則在Assembly中查找,如果是DirectoryCatalog,
在Directory 中查找,如果即想要在Assembly中查找,又需要在Directory中查找,
則采用AggregateCatalog。
3:然后在這堆Catalog中查找與Import 特性相對應(yīng)的Export標(biāo)記所標(biāo)記的實現(xiàn)類,調(diào)用實現(xiàn)類的構(gòu)造函數(shù)進(jìn)行
Composite(組合)。
知道原理后,你也可以自己實現(xiàn)自己的CompositionContainer 類了,
要使用MEF 需要為SimpleCalculator添加 System.ComponentModel.Composition.dll 的引用,
然后導(dǎo)入命名空間:
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
接下來看下Program 的構(gòu)造函數(shù)所做的事情:
聲明一個AssemblyCatalog,指向Program所在的Assembly. 然后把它添加到
CompositionContainer中,調(diào)用CompositionContainer 的ComposeParts 擴展方法,來Compose(this) 的Parts。
注:ComposeParts 是擴展方法,需要using System.ComponentModel.Composition;
OK,如何Compose,在哪個Assembly中查找實現(xiàn)類來進(jìn)行Compose已經(jīng)完成了。
目前的問題是:哪些類需要Compose??
為了回答這個問題,微軟提供了Import和Export特性:
Import:哪個對象需要Compose。也就是需要被實現(xiàn)類給填充,所以Import標(biāo)記的是對象,一般該對象是接口,因為如果是具體類的話,那還需要Import嗎?
Export:哪個類可以被用來Compose,也就是說這個類是不是可以用來填充的實現(xiàn)類,所以Export標(biāo)記的是類,而不是具體的某個對象。
所以在這里calculator 使用Import 特性來標(biāo)記:
[Import(typeof(ICalculator))]
private ICalculator calculator;
接下來MEF 的組合引擎在ComposeParts(this)的時候,就會在catalog 代表的AssemblyCatalog中查找Export特性所修飾的實現(xiàn)類了,找到實現(xiàn)類后進(jìn)行Compose。
如果找不到Export特性修飾的類的話,結(jié)果如下:
OK,接下來添加一個實現(xiàn)類,并使用Export特性來進(jìn)行修飾:
[Export(typeof(ICalculator))]
public class MySimpleCalculator : ICalculator
{
public string Calculate(string input)
{
return "MySimpleCalculator 處理了" + input;
}
}
運行結(jié)果如下:
當(dāng)然Import和Export還提供了其他的構(gòu)造函數(shù),所以你還可以將上面的Import和Export修改為:
[Import("calculator1", typeof(ICalculator))]
[Export("calculator1", typeof(ICalculator))]
之所以提供ContractName為calculator1 是因為你可能有多個ICalculator對象需要填充。
修改Program的代碼如下:
class Program
{
private CompositionContainer _container;
[Import("calculator1", typeof(ICalculator))]
private ICalculator calculator1;
[Import("calculator2", typeof(ICalculator))]
private ICalculator calculator2;
public Program()
{
//var catalog = new AggregateCatalog();
//catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
_container = new CompositionContainer(catalog);
try
{
this._container.ComposeParts(this);
}
catch(CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
static void Main(string[] args)
{
Program p = new Program();
string s;
Console.WriteLine("Enter Command:");
while (true)
{
s = Console.ReadLine();
Console.WriteLine(p.calculator1.Calculate(s));
Console.WriteLine(p.calculator2.Calculate(s));
}
}
}
修改Export修飾的類為:
[Export("calculator1", typeof(ICalculator))]
public class MySimpleCalculator1 : ICalculator
{
public string Calculate(string input)
{
return "第一個Calculator 處理了" + input;
}
}
[Export("calculator2", typeof(ICalculator))]
public class MySimpleCalculator2 : ICalculator
{
public string Calculate(string input)
{
return "第二個Calculator 處理了" + input;
}
}
運行結(jié)果如下:
因為Import和Export是一一對應(yīng)的,在現(xiàn)實世界中,存在著大量一對多的情況,微軟也預(yù)料到了這種情況,所以提供了ImportMany 特性。
在上個例子中的MySimpleCalculator的Calculate方法返回的是一句話,在這個例子中要真正實現(xiàn)計算的功能,例如輸入5+3,輸出8,輸入7*4,輸出28。
為了支持 + - * / 四種Operation.所以在MySimpleCalculator中聲明一個operations 的列表。
[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{
[ImportMany]
IEnumerable<Lazy<IOperation, IOperationData>> operations;
public string Calculate(string input)
{
return "calculate 處理了" + input;
}
}
之所以在MySimpleCalculator 中聲明operations ,是因為是計算器支持多種運算。因為operations 需要多個operation 來Compose(填充),所以使用ImportMany特性來修飾,和Import特性一樣,ImportMany特性一般也是修飾接口。
Ioperation 和IOperationData的定義如下:
public interface IOperation
{
int Operate(int left, int right);
}
public interface IOperationData
{
Char Symbol { get; }
}
Lazy<IOperation, IOperationData> operations:
提供對對象及其關(guān)聯(lián)的元數(shù)據(jù)的延遲間接引用,以供 Managed Extensibility Framework 使用。
意思是說IOperation 和IOperationData之間的引用需要延遲,為什么需要延遲?,因為IOperation需要根據(jù)IOperationData的Symbol符號來延遲創(chuàng)建。
也就是說,如果IOperationData的Symbol 等于 “+”,那么IOperation對象是AddOperation.如果IOperationData的Symbol等于”-”,那么IOperation對象是SubtractOperation.
那么如何保證這點呢?
關(guān)鍵點就在于ExportMetadata attribute 上。
看下Add Operation 的定義:
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '+')]
class Add : IOperation
{
public int Operate(int left, int right)
{
return left + right;
}
}
在這里ExportMetadata特性的Symbol 為+。所以當(dāng)IOperationData的Symbol為”+” 的時候,匹配的就是Add Operation
MySimpleCalculator 的完整代碼如下:
[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{
[ImportMany]
IEnumerable<Lazy<IOperation, IOperationData>> operations;
public string Calculate(string input)
{
int left;
int right;
char operation;
int fn = FindFirstNonDigitPosition(input);
if (fn < 0) return "Could not parse command.";
try
{
left = int.Parse(input.Substring(0, fn));
right = int.Parse(input.Substring(fn + 1));
}
catch
{
return "Could not parse command";
}
operation = input[fn];
foreach (Lazy<IOperation, IOperationData> i in operations)
{
if (i.Metadata.Symbol.Equals(operation))
return i.Value.Operate(left, right).ToString();
}
return "Operation Not Found!";
}
private int FindFirstNonDigitPosition(string s)
{
for (int i = 0; i < s.Length; i++)
{
if (!(Char.IsDigit(s[i]))) return i;
}
return -1;
}
}
回頭再看看上例的Program代碼:
class Program
{
private CompositionContainer _container;
[Import(typeof(ICalculator))]
private ICalculator calculator;
public Program()
{
//var catalog = new AggregateCatalog();
//catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
_container = new CompositionContainer(catalog);
try
{
this._container.ComposeParts(this);
}
catch(CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
static void Main(string[] args)
{
Program p = new Program();
string s;
Console.WriteLine("Enter Command:");
while (true)
{
s = Console.ReadLine();
Console.WriteLine(p.calculator.Calculate(s));
}
}
}
當(dāng)this._container.ComposeParts(this); 的時候,MEF組合引擎就開始對標(biāo)記了Import特性的接口進(jìn)行Compose,所以在這里是calculator。在哪里找實現(xiàn)類呢?,AssemblyCatalog表明在Program的當(dāng)前Assembly中查找實現(xiàn)類,所以找到了MySimpleCalculator在構(gòu)造MySimpleCalculator 的時候,發(fā)現(xiàn)了ImportMany特性修飾的operations。于是繼續(xù)在AssemblyCatalog中找到了Add。
上面的過程是Compose的過程。
那么MySimpleCalculator 如何進(jìn)行Calculate的呢?
例如5+3
1:找出第一個非數(shù)字的位置,也就是需要找出 +。
2:聲明left,right.并且left 為5,right為3.
3:根據(jù)符號+來構(gòu)造IOperation對象,接著調(diào)用IOperation對象的Operate(left,right)方法。
foreach (Lazy<IOperation, IOperationData> i in operations)
{
if (i.Metadata.Symbol.Equals(operation))
return i.Value.Operate(left, right).ToString();
}
運行結(jié)果:
因為目前定義了Add 的Operation。所以根據(jù)符號+ 能夠找到Add,但是*我們沒有定義,所以O(shè)peration Not Found!.
于是開始定義Multiple:
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '*')]
class Multiple : IOperation
{
public int Operate(int left, int right)
{
return left * right;
}
}
再次運行,結(jié)果如下:
當(dāng)然還可以在當(dāng)前程序集下面增加- ,/,^,% 等Operation。
為了讓事情更加的有趣,我打算在Debug目錄下增加一個目錄CalculateExtensions,然后將-,/ ..的Operation放到里面來,讓MEF自動發(fā)現(xiàn)。
首先新建類庫項目:SimpleCalculatorExtension
因為需要實現(xiàn)IOperation ,所以需要添加對SimpleCalculator項目的引用。
因為需要Export特性,所以需要添加對System.ComponentModel.Composition的引用。
整個項目的結(jié)果如下:
Subtract代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
namespace SimpleCalculatorExtension
{
[Export(typeof(SimpleCalculator.IOperation))]
[ExportMetadata("Symbol", '-')]
class Subtract : SimpleCalculator.IOperation
{
public int Operate(int left, int right)
{
return left - right;
}
}
}
生成成功后,將SimpleCalculatorExtension.dll 拷貝到CalculateExtensions目錄下:
現(xiàn)在SimpleCalculator的Debug目錄應(yīng)該是這樣。
并且CalculateExtensions文件夾下面有SimpleCalculatorExtension.dll.
接下來唯一要修改的是Program的catalog 對象。
為了讓catalog既支持在Program的Assembly中查找,又支持在CalculateExtensions目錄下查找。修改代碼如下:
public Program()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
catalog.Catalogs.Add(new DirectoryCatalog("CalculateExtensions"));
_container = new CompositionContainer(catalog);
try
{
this._container.ComposeParts(this);
}
catch(CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
運行結(jié)果如下:
修改SimpleCalculatorExtension 的Subtract方法為:
namespace SimpleCalculatorExtension
{
[Export(typeof(SimpleCalculator.IOperation))]
[ExportMetadata("Symbol", '-')]
class Subtract : SimpleCalculator.IOperation
{
public int Operate(int left, int right)
{
Console.WriteLine("SimpleCalculatorExtension的方法");
return left - right;
}
}
}
重新生成SimpleCalculatorExtension.dll 然后拷貝到CalculateExtensions 文件夾下:
再次運行程序,輸出入下:
文章有點長,而且有點亂,最好自己動手實踐下MEF,不過講的都是MEF的基礎(chǔ),希望對你有所幫助,另外如果你不使用MEF,采用面向接口的編程原則的話,相信你自己也很容易實現(xiàn)自己的“MEF”
】:
以實例說話,一起體驗MEF帶來的可擴展性吧,Let's Rock?。。?/STRONG>
1:新建控制臺程序SimpleCalculator
在這里要實現(xiàn)的程序時SimpleCalculator,顧名思義:簡單的計算器。
所以我們需要定義一個用來計算的接口:
public interface ICalculator
{
String Calculate(String input);
}
Program 的代碼如下:
class Program
{
private CompositionContainer _container;
[Import(typeof(ICalculator))]
private ICalculator calculator;
public Program()
{
//var catalog = new AggregateCatalog();
//catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
_container = new CompositionContainer(catalog);
try
{
this._container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
static void Main(string[] args)
{
Program p = new Program();
string s;
Console.WriteLine("Enter Command:");
while (true)
{
s = Console.ReadLine();
Console.WriteLine(p.calculator.Calculate(s));
}
}
}
MEF所要解決的是尋找插件的功能,傳統(tǒng)的實現(xiàn)插件的方式主要是使用接口,即聲明一個接口,然后使用配置文件來配置接口使用哪個實現(xiàn)類。
微軟知道有這種需求,于是提供了MEF來實現(xiàn)插件的功能。
Composite 原理:
1:聲明一個 CompositionContainer 對象,這個對象里面包含一堆Catalog.
2:這堆Catalog如果是AssemblyCatalog,則在Assembly中查找,如果是DirectoryCatalog,
在Directory 中查找,如果即想要在Assembly中查找,又需要在Directory中查找,
則采用AggregateCatalog。
3:然后在這堆Catalog中查找與Import 特性相對應(yīng)的Export標(biāo)記所標(biāo)記的實現(xiàn)類,調(diào)用實現(xiàn)類的構(gòu)造函數(shù)進(jìn)行
Composite(組合)。
知道原理后,你也可以自己實現(xiàn)自己的CompositionContainer 類了,
要使用MEF 需要為SimpleCalculator添加 System.ComponentModel.Composition.dll 的引用,
然后導(dǎo)入命名空間:
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
接下來看下Program 的構(gòu)造函數(shù)所做的事情:
聲明一個AssemblyCatalog,指向Program所在的Assembly. 然后把它添加到
CompositionContainer中,調(diào)用CompositionContainer 的ComposeParts 擴展方法,來Compose(this) 的Parts。
注:ComposeParts 是擴展方法,需要using System.ComponentModel.Composition;
OK,如何Compose,在哪個Assembly中查找實現(xiàn)類來進(jìn)行Compose已經(jīng)完成了。
目前的問題是:哪些類需要Compose??
為了回答這個問題,微軟提供了Import和Export特性:
Import:哪個對象需要Compose。也就是需要被實現(xiàn)類給填充,所以Import標(biāo)記的是對象,一般該對象是接口,因為如果是具體類的話,那還需要Import嗎?
Export:哪個類可以被用來Compose,也就是說這個類是不是可以用來填充的實現(xiàn)類,所以Export標(biāo)記的是類,而不是具體的某個對象。
所以在這里calculator 使用Import 特性來標(biāo)記:
[Import(typeof(ICalculator))]
private ICalculator calculator;
接下來MEF 的組合引擎在ComposeParts(this)的時候,就會在catalog 代表的AssemblyCatalog中查找Export特性所修飾的實現(xiàn)類了,找到實現(xiàn)類后進(jìn)行Compose。
如果找不到Export特性修飾的類的話,結(jié)果如下:
OK,接下來添加一個實現(xiàn)類,并使用Export特性來進(jìn)行修飾:
[Export(typeof(ICalculator))]
public class MySimpleCalculator : ICalculator
{
public string Calculate(string input)
{
return "MySimpleCalculator 處理了" + input;
}
}
運行結(jié)果如下:
當(dāng)然Import和Export還提供了其他的構(gòu)造函數(shù),所以你還可以將上面的Import和Export修改為:
[Import("calculator1", typeof(ICalculator))]
[Export("calculator1", typeof(ICalculator))]
之所以提供ContractName為calculator1 是因為你可能有多個ICalculator對象需要填充。
修改Program的代碼如下:
class Program
{
private CompositionContainer _container;
[Import("calculator1", typeof(ICalculator))]
private ICalculator calculator1;
[Import("calculator2", typeof(ICalculator))]
private ICalculator calculator2;
public Program()
{
//var catalog = new AggregateCatalog();
//catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
_container = new CompositionContainer(catalog);
try
{
this._container.ComposeParts(this);
}
catch(CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
static void Main(string[] args)
{
Program p = new Program();
string s;
Console.WriteLine("Enter Command:");
while (true)
{
s = Console.ReadLine();
Console.WriteLine(p.calculator1.Calculate(s));
Console.WriteLine(p.calculator2.Calculate(s));
}
}
}
修改Export修飾的類為:
[Export("calculator1", typeof(ICalculator))]
public class MySimpleCalculator1 : ICalculator
{
public string Calculate(string input)
{
return "第一個Calculator 處理了" + input;
}
}
[Export("calculator2", typeof(ICalculator))]
public class MySimpleCalculator2 : ICalculator
{
public string Calculate(string input)
{
return "第二個Calculator 處理了" + input;
}
}
運行結(jié)果如下:
因為Import和Export是一一對應(yīng)的,在現(xiàn)實世界中,存在著大量一對多的情況,微軟也預(yù)料到了這種情況,所以提供了ImportMany 特性。
在上個例子中的MySimpleCalculator的Calculate方法返回的是一句話,在這個例子中要真正實現(xiàn)計算的功能,例如輸入5+3,輸出8,輸入7*4,輸出28。
為了支持 + - * / 四種Operation.所以在MySimpleCalculator中聲明一個operations 的列表。
[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{
[ImportMany]
IEnumerable<Lazy<IOperation, IOperationData>> operations;
public string Calculate(string input)
{
return "calculate 處理了" + input;
}
}
之所以在MySimpleCalculator 中聲明operations ,是因為是計算器支持多種運算。因為operations 需要多個operation 來Compose(填充),所以使用ImportMany特性來修飾,和Import特性一樣,ImportMany特性一般也是修飾接口。
Ioperation 和IOperationData的定義如下:
public interface IOperation
{
int Operate(int left, int right);
}
public interface IOperationData
{
Char Symbol { get; }
}
Lazy<IOperation, IOperationData> operations:
提供對對象及其關(guān)聯(lián)的元數(shù)據(jù)的延遲間接引用,以供 Managed Extensibility Framework 使用。
意思是說IOperation 和IOperationData之間的引用需要延遲,為什么需要延遲?,因為IOperation需要根據(jù)IOperationData的Symbol符號來延遲創(chuàng)建。
也就是說,如果IOperationData的Symbol 等于 “+”,那么IOperation對象是AddOperation.如果IOperationData的Symbol等于”-”,那么IOperation對象是SubtractOperation.
那么如何保證這點呢?
關(guān)鍵點就在于ExportMetadata attribute 上。
看下Add Operation 的定義:
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '+')]
class Add : IOperation
{
public int Operate(int left, int right)
{
return left + right;
}
}
在這里ExportMetadata特性的Symbol 為+。所以當(dāng)IOperationData的Symbol為”+” 的時候,匹配的就是Add Operation
MySimpleCalculator 的完整代碼如下:
[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{
[ImportMany]
IEnumerable<Lazy<IOperation, IOperationData>> operations;
public string Calculate(string input)
{
int left;
int right;
char operation;
int fn = FindFirstNonDigitPosition(input);
if (fn < 0) return "Could not parse command.";
try
{
left = int.Parse(input.Substring(0, fn));
right = int.Parse(input.Substring(fn + 1));
}
catch
{
return "Could not parse command";
}
operation = input[fn];
foreach (Lazy<IOperation, IOperationData> i in operations)
{
if (i.Metadata.Symbol.Equals(operation))
return i.Value.Operate(left, right).ToString();
}
return "Operation Not Found!";
}
private int FindFirstNonDigitPosition(string s)
{
for (int i = 0; i < s.Length; i++)
{
if (!(Char.IsDigit(s[i]))) return i;
}
return -1;
}
}
回頭再看看上例的Program代碼:
class Program
{
private CompositionContainer _container;
[Import(typeof(ICalculator))]
private ICalculator calculator;
public Program()
{
//var catalog = new AggregateCatalog();
//catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
_container = new CompositionContainer(catalog);
try
{
this._container.ComposeParts(this);
}
catch(CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
static void Main(string[] args)
{
Program p = new Program();
string s;
Console.WriteLine("Enter Command:");
while (true)
{
s = Console.ReadLine();
Console.WriteLine(p.calculator.Calculate(s));
}
}
}
當(dāng)this._container.ComposeParts(this); 的時候,MEF組合引擎就開始對標(biāo)記了Import特性的接口進(jìn)行Compose,所以在這里是calculator。在哪里找實現(xiàn)類呢?,AssemblyCatalog表明在Program的當(dāng)前Assembly中查找實現(xiàn)類,所以找到了MySimpleCalculator在構(gòu)造MySimpleCalculator 的時候,發(fā)現(xiàn)了ImportMany特性修飾的operations。于是繼續(xù)在AssemblyCatalog中找到了Add。
上面的過程是Compose的過程。
那么MySimpleCalculator 如何進(jìn)行Calculate的呢?
例如5+3
1:找出第一個非數(shù)字的位置,也就是需要找出 +。
2:聲明left,right.并且left 為5,right為3.
3:根據(jù)符號+來構(gòu)造IOperation對象,接著調(diào)用IOperation對象的Operate(left,right)方法。
foreach (Lazy<IOperation, IOperationData> i in operations)
{
if (i.Metadata.Symbol.Equals(operation))
return i.Value.Operate(left, right).ToString();
}
運行結(jié)果:
因為目前定義了Add 的Operation。所以根據(jù)符號+ 能夠找到Add,但是*我們沒有定義,所以O(shè)peration Not Found!.
于是開始定義Multiple:
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '*')]
class Multiple : IOperation
{
public int Operate(int left, int right)
{
return left * right;
}
}
再次運行,結(jié)果如下:
當(dāng)然還可以在當(dāng)前程序集下面增加- ,/,^,% 等Operation。
為了讓事情更加的有趣,我打算在Debug目錄下增加一個目錄CalculateExtensions,然后將-,/ ..的Operation放到里面來,讓MEF自動發(fā)現(xiàn)。
首先新建類庫項目:SimpleCalculatorExtension
因為需要實現(xiàn)IOperation ,所以需要添加對SimpleCalculator項目的引用。
因為需要Export特性,所以需要添加對System.ComponentModel.Composition的引用。
整個項目的結(jié)果如下:
Subtract代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
namespace SimpleCalculatorExtension
{
[Export(typeof(SimpleCalculator.IOperation))]
[ExportMetadata("Symbol", '-')]
class Subtract : SimpleCalculator.IOperation
{
public int Operate(int left, int right)
{
return left - right;
}
}
}
生成成功后,將SimpleCalculatorExtension.dll 拷貝到CalculateExtensions目錄下:
現(xiàn)在SimpleCalculator的Debug目錄應(yīng)該是這樣。
并且CalculateExtensions文件夾下面有SimpleCalculatorExtension.dll.
接下來唯一要修改的是Program的catalog 對象。
為了讓catalog既支持在Program的Assembly中查找,又支持在CalculateExtensions目錄下查找。修改代碼如下:
public Program()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
catalog.Catalogs.Add(new DirectoryCatalog("CalculateExtensions"));
_container = new CompositionContainer(catalog);
try
{
this._container.ComposeParts(this);
}
catch(CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
運行結(jié)果如下:
修改SimpleCalculatorExtension 的Subtract方法為:
namespace SimpleCalculatorExtension
{
[Export(typeof(SimpleCalculator.IOperation))]
[ExportMetadata("Symbol", '-')]
class Subtract : SimpleCalculator.IOperation
{
public int Operate(int left, int right)
{
Console.WriteLine("SimpleCalculatorExtension的方法");
return left - right;
}
}
}
重新生成SimpleCalculatorExtension.dll 然后拷貝到CalculateExtensions 文件夾下:
再次運行程序,輸出入下:
文章有點長,而且有點亂,最好自己動手實踐下MEF,不過講的都是MEF的基礎(chǔ),希望對你有所幫助,另外如果你不使用MEF,采用面向接口的編程原則的話,相信你自己也很容易實現(xiàn)自己的“MEF”
相關(guān)文章
畢業(yè)論文-客戶關(guān)系管理與數(shù)據(jù)挖掘技術(shù)綜述
畢業(yè)論文-客戶關(guān)系管理與數(shù)據(jù)挖掘技術(shù)綜述...2007-03-03畢業(yè)論文-如何預(yù)防計算機的網(wǎng)絡(luò)病毒
畢業(yè)論文-如何預(yù)防計算機的網(wǎng)絡(luò)病毒...2007-03-03畢業(yè)論文-大型的WEB應(yīng)用程序開發(fā)
畢業(yè)論文-大型的WEB應(yīng)用程序開發(fā)...2007-03-03畢業(yè)論文-電子商務(wù)罪在何處?--淺談有關(guān)電子商務(wù)認(rèn)識的幾個誤區(qū)
畢業(yè)論文-電子商務(wù)罪在何處?--淺談有關(guān)電子商務(wù)認(rèn)識的幾個誤區(qū)...2007-03-03