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

posted on 2013-01-16 21:58  PetterLiu  阅读(3831)  评论(4编辑  收藏  举报