Managed Extensibility Framework (MEF) 是.NET的一個組合框架,用於增強復雜應用的模塊化和可擴展性。從.net framework 4.0 開始集成的組件。到目前為止,MEF的歷史上最重要的應用程序是Visual Studio 2010。許多特性都是為了滿足Visual Studio里的編輯器的需求,比如說,延遲加載所有東西和細粒度協定。MEF的工作原理簡單來看是這樣的:
現在 MEF 2.0 版本已集成於.net framework 4.5。 除了以前Import, Export等Attribute,增加的特性包括
1. 基於約定的編程模型,支持命名約定
2. 支持泛型
3. 支持多個范圍
好的,先讓我們來看新特性之約定的編程模型,假設這樣的簡單模型類圖:
public class GreatEditor
{
public ILogPlugin Logger { get; set; }
public ISavePlugin Saver { get; set; }
}
public interface ILogPlugin
{
void Write(string message);
}
public class LoggerPlugin : ILogPlugin
{
public void Write(string message)
{
Console.WriteLine("Logger {0}", message);
}
}
public interface ISavePlugin
{
void Save(string message);
}
public class FilePlugin : ISavePlugin
{
public void Save(string message)
{
Console.WriteLine("FilePlugin {0}", message);
}
}
上面定義幾個簡單的Interface,一個名叫GreatEditor客戶類引用兩個interface,我們通常做法就是在屬性實現依賴注入。另請你有注意這里沒有使用MEF中的相關Attribute,因為下面我們使用新特性來實現,在代碼是這樣:
private static void FluentExportInterfaceDemo()
{
Program program = new Program();
var picker = new RegistrationBuilder();
picker.ForTypesMatching(pl => pl.Name.EndsWith("Plugin"))
.ExportInterfaces();
var catalog = new AssemblyCatalog(typeof(Program).Assembly, picker);
var container = new CompositionContainer(catalog);
container.ComposeParts(program);
var log = container.GetExportedValue<ILogPlugin>();
var save = container.GetExportedValue<ISavePlugin>();
save.Save("test");
log.Write("test");
}
注意首先您需要引用以下namespace:
using System.Reflection.Context;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Registration;
類似IOC組件,這里使用命名約定以字符串”Plugin” 結束的Type,Fluent配置風格。然后使用AssemblyCatalog裝載Program的Assembly,接着GetExportedValue方法取得我們目前基類型,執行客戶方法驗證是否是我們想要的結果。
如果您想Import屬性,那是這樣的:
private static void FluentImportPropertiesDemo()
{
var picker = new RegistrationBuilder();
picker.ForTypesDerivedFrom<ILogPlugin>()
.Export<ILogPlugin>();
picker.ForType<GreatEditor>()
.Export().ImportProperties<ILogPlugin>(pi => pi.Name == "Logger",
(propInfo, builder) =>
{
builder.AllowRecomposition();
builder.RequiredCreationPolicy(CreationPolicy.NonShared);
});
var catalog = new AssemblyCatalog(typeof(Program).Assembly, picker);
var container = new CompositionContainer(catalog);
container.Compose(new CompositionBatch());
var editor = container.GetExportedValue<GreatEditor>();
editor.Logger.Write("Let it go");
}
如果想ExportMany類型,這里我們使用.net framwork自帶加密類做演示:
[Export]
public class AlgorithmCollection
{
[ImportMany]
public SymmetricAlgorithm[] CryptoProviders { get; private set; }
}
public class CryptoComposer
{
public SymmetricAlgorithm Aes { get { return new AesManaged(); } }
public SymmetricAlgorithm TripleDES { get { return new TripleDESCryptoServiceProvider(); } }
public SymmetricAlgorithm RC2 { get { return new RC2CryptoServiceProvider(); } }
}
看到上面標記ImportMany的Attribute, 對應這里是SymmetricAlgorithm Array類型,接着 調用方法如下:
private static void FluentMultiExportPropertiesDemo()
{
var picker = new RegistrationBuilder();
picker.ForType<CryptoComposer>()
.ExportProperties(p => p.PropertyType == typeof(SymmetricAlgorithm));
var catalog = new AssemblyCatalog(typeof(Program).Assembly, picker);
var container = new CompositionContainer(catalog);
var foo = container.GetExportedValue<AlgorithmCollection>();
//output for debug
foo.CryptoProviders.ToList().ForEach(pr => Console.WriteLine(pr));
}
還有構造器Import的情況,假設有這樣的Model:
public interface ILogger
{
void Write(string message);
}
public class Logger : ILogger
{
public void Write(string message) {
Console.WriteLine("Log with console : {0}", message);
}
}
public class Worker
{
private ILogger _logger;
public Worker(){}
public Worker(ILogger logger)
{
_logger = logger;
}
public void Execute(string message)
{
_logger.Write(message);
}
}
注意上面Work有一個有參的構造方法,調用的代碼是這樣的:
private static void FluentImportConstructorDemo()
{
var picker = new RegistrationBuilder();
picker.ForTypesDerivedFrom<ILogger>()
.Export<ILogger>();
picker.ForType<Worker>()
.SelectConstructor(ctors => ctors.First(info => info.GetParameters().Length == 1))
.Export();
var catalog = new AssemblyCatalog(typeof(Program).Assembly, picker);
var container = new CompositionContainer(catalog);
container.Compose(new CompositionBatch());
var worker = container.GetExportedValue<Worker>();
worker.Execute("Let it go");
}
上面的代碼有注意使用SelectConstructor方法,選擇有參數的構造器。
最后對於泛型的支持例子是這樣的:
public class FooWithOpenGeneric
{
[Import]
public EventAggregator<int> IntAggregator { get; set; }
}
[Export]
public class EventAggregator<T>
{
public event Action<T> Notify = (item) => { };
public void Send(T item)
{
Notify(item);
}
}
如果了解泛型Generic不難看懂,調用代碼:
private static void WorkWithOpenGeneric()
{
var picker = new RegistrationBuilder();
picker.ForType<FooWithOpenGeneric>()
.Export();
var catalog = new AssemblyCatalog(typeof(Program).Assembly, picker);
var container = new CompositionContainer(catalog);
container.Compose(new CompositionBatch());
var fooWithOpenGeneric = container.GetExportedValue<FooWithOpenGeneric>();
}
全部Demo方法合並在一起測試下:
static void Main(string[] args)
{
WorkWithOpenGeneric();
FluentImportConstructorDemo();
FluentExportInterfaceDemo();
FluentImportPropertiesDemo();
FluentMultiExportPropertiesDemo();
Console.Read();
}
通過上面代碼演示,對MEF 2.0的兩個新特性有一定了解吧,代碼在 Visual Studio 2012, .net framework 4.5 測式通過。MEF在實際開發做為輕量級的組件實現基於Plugin開發,使得你的程序具有可擴展性,重用性。關於MEF更詳細的內容可參考MSDN. MEF 2 實現了Plugin模式,最難得是現在集成於 .net framework 4.5 中,它還有一個子集版本支持Win 8 Metro App開發。
你可參感興趣文章:
Pluge模式
使用Fluent配置API驅動Enterprise Library 5.0
EneterpriseLibrary5的Fluent配制API
作者:Petter Liu
出處:http://www.cnblogs.com/wintersun/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
該文章也同時發布在我的獨立博客中-Petter Liu Blog。