Managed Extensibility Framework(MEF) 2 框架新特性介紹


      Managed Extensibility Framework (MEF) 是.NET的一個組合框架,用於增強復雜應用的模塊化和可擴展性。從.net framework 4.0 開始集成的組件。到目前為止,MEF的歷史上最重要的應用程序是Visual Studio 2010。許多特性都是為了滿足Visual Studio里的編輯器的需求,比如說,延遲加載所有東西和細粒度協定。MEF的工作原理簡單來看是這樣的:

MEFChart1

現在 MEF 2.0 版本已集成於.net framework 4.5。 除了以前Import, Export等Attribute,增加的特性包括

1. 基於約定的編程模型,支持命名約定

2. 支持泛型

3. 支持多個范圍

好的,先讓我們來看新特性之約定的編程模型,假設這樣的簡單模型類圖:

GreatEditorD

    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:

Wokerd

    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


免責聲明!

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



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