MEF学习

一、   什么是MEF

  MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库。 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置。 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项。 通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。(摘自MSDN)

  我的理解:应用/插件均使用约定好的协议(接口)进行开发。系统将自动扫描指定文件夹,并按协议自动导入。

二、   MEF简单例子

1、例子一

a、定义接口

 public interface DemoOneInterface   
    {
        void Send(string msg);
    }

b、使用接口

    public class DemoOne
    {
        [Import]
        DemoOneInterface DO;

        public void Run()
        {
            DO.Send("DemoOne.Run");
        }
    }
使用[Import]标记需要导入属性(DemoOneInterface DO;),如果不标记,则MEF不会进行导入。

c、创建插件类

    [Export(typeof(DemoOneInterface))]
    public class DemoOneInherit1 : DemoOneInterface
    {

        #region DemoOneInterface Members

        public void Send(string msg)
        {
            Console.WriteLine("DemoOneInherit1 send {0}", msg);
        }

        #endregion
    }
插件

 插件类需要使用Export标记,并且声称导出类型。 

d、查看效果

  static void Main(string[] args)
        {
            new DemoOne().Run();

            Console.ReadLine();
        }

 

原来我们使用MEF,但并没有通知MEF去寻找插件。

我们对Main函数进行修改:

var demo = new DemoOne();

            var catalog = new AggregateCatalog();

            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

            //catalog.Catalogs.Add(new DirectoryCatalog("Addin"));   //遍历运行目录下的Addin文件夹,查找所需的插件。

            var _container = new CompositionContainer(catalog);

            _container.ComposeParts(demo);
            
            demo.Run();

 

修改后再次运行看看效果。

OK,运行起来了,和预期一样。

 

2、例子二

运行例子一,没有问题,但2个插件使用同一个的时候,会报错。

因此我们可以为Export加入别名(contractName),并且Import的时候也指定别名,MEF就会根据别名自动进行加载。

修改后代码如下:

public class DemoOne
    {
        [Import("2")]
        DemoOneInterface DO;

        public void Run()
        {
            DO.Send("DemoOne.Run");
        }
    }

    public interface DemoOneInterface   
    {
        void Send(string msg);
    }

    [Export("1",typeof(DemoOneInterface))]
    public class DemoOneInherit1 : DemoOneInterface
    {

        #region DemoOneInterface Members

        public void Send(string msg)
        {
            Console.WriteLine("DemoOneInherit1 send {0}", msg);
        }

        #endregion
    }



    [Export("2", typeof(DemoOneInterface))]
    public class DemoOneInherit12 : DemoOneInterface
    {

        #region DemoOneInterface Members

        public void Send(string msg)
        {
            Console.WriteLine("DemoOneInherit2 send {0}", msg);
        }

        #endregion
    }
View Code

 

 运行效果:

3、例子三

有时我们希望一个同时使用多个插件,比如:输出log。

这时我们可以将Import改为ImportMany,并且修改Do的类型为IEnumerable<DemoOneInterface>来导入多个插件。

修改后代码:

   public class DemoOne
    {
        [ImportMany]
        IEnumerable<DemoOneInterface> DoList;

        public void Run()
        {
            foreach (var _do in DoList)
            {
                _do.Send("DemoOne.Run");
            }
        }
    }

    public interface DemoOneInterface   
    {
        void Send(string msg);
    }

    [Export(typeof(DemoOneInterface))]
    public class DemoOneInherit1 : DemoOneInterface
    {

        #region DemoOneInterface Members

        public void Send(string msg)
        {
            Console.WriteLine("DemoOneInherit1 send {0}", msg);
        }

        #endregion
    }



    [Export(typeof(DemoOneInterface))]
    public class DemoOneInherit12 : DemoOneInterface
    {

        #region DemoOneInterface Members

        public void Send(string msg)
        {
            Console.WriteLine("DemoOneInherit2 send {0}", msg);
        }

        #endregion
    }
View Code

 

运行效果:

4、例子四

现在有很多插件使用同一个约定,但我想根据配置在同一个方法中调用某个插件。

这时我们需要使用ExportMetadata来为插件的特殊属性进行标记。

使用到Lazy,来进行延迟加载,并且获取插件标记的信息。(关于Lazy具体信息请自行查找)

a、新增插件描述类

    public interface DemoOneInterfaceDepict
    {
        string Depict{get;}
    }

 

b、为插件定义描述

 [Export(typeof(DemoOneInterface))]
    [ExportMetadata("Depict", "1")]
    public class DemoOneInherit1 : DemoOneInterface
    {

        #region DemoOneInterface Members

        public void Send(string msg)
        {
            Console.WriteLine("DemoOneInherit1 send {0}", msg);
        }

        #endregion
    }



    [Export(typeof(DemoOneInterface))]
    [ExportMetadata("Depict", "2")]
    public class DemoOneInherit12 : DemoOneInterface
    {

        #region DemoOneInterface Members

        public void Send(string msg)
        {
            Console.WriteLine("DemoOneInherit2 send {0}", msg);
        }

        #endregion
    }
View Code

 

c、修改DoList

IEnumerable<Lazy<DemoOneInterface,DemoOneInterfaceDepict>> DoList;

d、根据配置调用 

 public class DemoOne
    {
        [ImportMany]
        IEnumerable<Lazy<DemoOneInterface,DemoOneInterfaceDepict>> DoList;

        public void Run()
        {
            foreach (var _do in DoList.Where(item=>item.Metadata.Depict == ReadXml()))
            {
                _do.Value.Send("DemoOne.Run");
            }
        }

        string ReadXml()
        {
            return "2";
        }
    }

 

运行结果:

 

三、简化调用

上述4个例子运行正常,但我们一直没去在意Main函数里面的内容。

 var demo = new DemoOne();

            var catalog = new AggregateCatalog();

            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

            //catalog.Catalogs.Add(new DirectoryCatalog("Addin"));   //遍历运行目录下的Addin文件夹,查找所需的插件。

            var _container = new CompositionContainer(catalog);

            _container.ComposeParts(demo);
            
            demo.Run();

 

看着头就晕了,难道每次构造一个函数,都这么写吗?那不是非常痛苦?!!!

重新设计一下:

1、使用基类

    public abstract class BaseClass
    {
        public BaseClass()
        {
            var catalog = new AggregateCatalog();

            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

            var _container = new CompositionContainer(catalog);

            _container.ComposeParts(this);
        }
    }

 

修改DemoOne类继承BaseClass

 public class DemoOne : BaseClass

 

简化调用

 var demo = new DemoOne();
 demo.Run();

 

运行 ok。

 

2、使用扩展方法

每个类都要继承这个基类,由于C#只有单继承,已经继承了一个基类后,就比较麻烦。

因此衍生出第二种方法,新增扩展方法。

扩展方法

public static class ObjectExt
    {
        public static T ComposePartsSelf<T>(this T obj) where T : class
        {
            var catalog = new AggregateCatalog();

            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
            catalog.Catalogs.Add(new DirectoryCatalog("."));
            //catalog.Catalogs.Add(new DirectoryCatalog("addin"));

            var _container = new CompositionContainer(catalog);

            _container.ComposeParts(obj);

            return obj;
        }
    }

 

修改DemoOne类,新增构造函数,并且调用扩展方法

  public class DemoOne 
    {
        public DemoOne()
        {
            this.ComposePartsSelf();
        }

        [ImportMany]
        IEnumerable<Lazy<DemoOneInterface,DemoOneInterfaceDepict>> DoList;

        public void Run()
        {
            foreach (var _do in DoList.Where(item=>item.Metadata.Depict == ReadXml()))
            {
                _do.Value.Send("DemoOne.Run");
            }
        }

        string ReadXml()
        {
            return "2";
        }
    }

 

简化调用

 var demo = new DemoOne();
 demo.Run();

运行 ok。

 

posted on 2014-09-24 16:31  CosmoKey  阅读(25375)  评论(9编辑  收藏  举报

导航