zoukankan      html  css  js  c++  java
  • MEF

    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
        }
    复制代码

     运行效果:

    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
        }
    复制代码

    运行效果:

    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
        }
    复制代码

    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。

     
    分类: C#
    标签: MEF学习MEFMEF 学习
  • 相关阅读:
    Understanding about Baire Category Theorem
    Isometric embedding of metric space
    Convergence theorems for measurable functions
    Mindmap for "Principles of boundary element methods"
    Various formulations of Maxwell equations
    Existence and uniqueness theorems for variational problems
    Kernels and image sets for an operator and its dual
    [loj6498]农民
    [luogu3781]切树游戏
    [atAGC051B]Three Coins
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3992738.html
Copyright © 2011-2022 走看看