【C#进阶系列】【MEF框架(二)】

C#进阶系列

第二章 【C#进阶系列】【MEF框架(二)】
第一章 【C#进阶系列】【MEF框架(一)】



前言

在(一)已经对MEF作了基本的介绍,这里针对MEF的导出[Export]和导入[Import]作一些补充。


一、不使用Export

在接口上面写注解,这样只要实现了这个接口的类都会导出,而不需要在每个类上面都写注解
如下代码,在接口中添加[InheritedExport]特性,实现类的Export已经注释掉了,最终效果仍然一样。
注意:这种方法虽然比较简单,但是只适用于比较简单的应用

namespace MEF_P1
{
    
    
    [InheritedExport]
    public interface IBookService
    {
    
    
        string GetBookName();
    }
    //[Export(typeof(IBookService))]
    public class MathBook : IBookService
    {
    
    
        public string GetBookName()
        {
    
    
            return "MathBook";
        }
    }
    class Program
    {
    
    
        [Import]
        public IBookService Service {
    
     get; set; }
        static void Main(string[] args)
        {
    
    
            Program pro = new Program();
            pro.Compose();
            if (pro.Service != null)
            {
    
    
                Console.WriteLine(pro.Service.GetBookName());
            }
            Console.Read();
        }
        private void Compose()
        {
    
    
            //创建一个程序集目录,用于从一个程序集获取所有的组件定义
            AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            //创建容器
            CompositionContainer container = new CompositionContainer(catalog);
            //组合部件:如果该类有Import,就会自动去寻找Export
            container.ComposeParts(this);
        }
    }
}

二、使用Export

直接看下面代码示例:

namespace MEF_P1
{
    
    
    public interface IBookService
    {
    
    
        string GetBookName();
    }
    [Export(typeof(IBookService))]
    public class MathBook : IBookService
    {
    
    
        public string GetBookName()
        {
    
    
            return "MathBook";
        }
    }
    class Program
    {
    
    
        [Import]
        public IBookService Service {
    
     get; set; }
        static void Main(string[] args)
        {
    
    
            Program pro = new Program();
            pro.Compose();
            if (pro.Service != null)
            {
    
    
                Console.WriteLine(pro.Service.GetBookName());
            }
            Console.Read();
        }
        private void Compose()
        {
    
    
            //创建一个程序集目录,用于从一个程序集获取所有的组件定义
            AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            //创建容器
            CompositionContainer container = new CompositionContainer(catalog);
            //组合部件:如果该类有Import,就会自动去寻找Export
            container.ComposeParts(this);
        }
    }
}

三、使用多个Export

如果存在多个Export,那就要使用[ImportMany]来代替[Import],再使用for循环逐个输出:

namespace MEF_P1
{
    
    
    public interface IBookService
    {
    
    
        string GetBookName();
    }
    [Export(typeof(IBookService))]
    public class MathBook : IBookService
    {
    
    
        public string GetBookName()
        {
    
    
            return "MathBook";
        }
    }
    [Export(typeof(IBookService))]
    public class ChineseBook : IBookService
    {
    
    
        public string GetBookName()
        {
    
    
            return "ChineseBook";
        }
    }
    class Program
    {
    
    
        [ImportMany]
        public IEnumerable<IBookService> Services {
    
     get; set; }
        static void Main(string[] args)
        {
    
    
            Program pro = new Program();
            pro.Compose();
            foreach (IBookService service in pro.Services)
            {
    
    
                Console.WriteLine(service.GetBookName());
            }
            Console.Read();
        }
        private void Compose()
        {
    
    
            //创建一个程序集目录,用于从一个程序集获取所有的组件定义
            AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            //创建容器
            CompositionContainer container = new CompositionContainer(catalog);
            //组合部件:如果该类有Import,就会自动去寻找Export
            container.ComposeParts(this);
        }
    }
}

四、使用Export带参数

[Export(“ContractName”,typeof(InterfaceName))]
多出了一个参数,其实就是契约名,理论上名字可以随便起,而且可以重复,但是如果名字乱起,和其他DLL中的契约名重复,会导致程序出现很多BUG,所以这个名字一定要按照一定的规范命名。

有了契约名之后,导入[Import]时就要指定契约名,否则无法找到Export了

namespace MEF_P1
{
    
    
    public interface IBookService
    {
    
    
        string GetBookName();
    }
    [Export("ContractName_MathBook", typeof(IBookService))]
    public class MathBook : IBookService
    {
    
    
        public string GetBookName()
        {
    
    
            return "MathBook";
        }
    }
    [Export("ContractName_ChineseBook", typeof(IBookService))]
    public class ChineseBook : IBookService
    {
    
    
        public string GetBookName()
        {
    
    
            return "ChineseBook";
        }
    }
    class Program
    {
    
    
        [Import("ContractName_MathBook")]
        public IBookService Services_MathBook {
    
     get; set; }
        [Import("ContractName_ChineseBook")]
        public IBookService Services_ChineseBook {
    
     get; set; }
        static void Main(string[] args)
        {
    
    
            Program pro = new Program();
            pro.Compose();
            if (pro.Services_MathBook != null)
            {
    
    
                Console.WriteLine(pro.Services_MathBook.GetBookName());
            }
            if (pro.Services_ChineseBook != null)
            {
    
    
                Console.WriteLine(pro.Services_ChineseBook.GetBookName());
            }
            Console.Read();
        }
        private void Compose()
        {
    
    
            //创建一个程序集目录,用于从一个程序集获取所有的组件定义
            AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            //创建容器
            CompositionContainer container = new CompositionContainer(catalog);
            //组合部件:如果该类有Import,就会自动去寻找Export
            container.ComposeParts(this);
        }
    }
}

五、不使用Import

获取Export的方式
可以用过Import+container.ComposeParts(this)方式
也可以直接使用container.GetExportedValue(ContractName);方式

namespace MEF_P1
{
    
    
    public interface IBookService
    {
    
    
        string GetBookName();
    }
    [Export("ContractName_MathBook")]
    public class MathBook : IBookService
    {
    
    
        public string GetBookName()
        {
    
    
            return "MathBook";
        }
    }
    [Export("ContractName_ChineseBook")]
    public class ChineseBook : IBookService
    {
    
    
        public string GetBookName()
        {
    
    
            return "ChineseBook";
        }
    }
    class Program
    {
    
    
        public object Services_MathBook {
    
     get; set; }
        public object Services_ChineseBook {
    
     get; set; }
        static void Main(string[] args)
        {
    
    
            Program pro = new Program();
            pro.Compose();
            if (pro.Services_MathBook != null)
            {
    
    
                Console.WriteLine(((IBookService)pro.Services_MathBook).GetBookName());
            }
            if (pro.Services_ChineseBook != null)
            {
    
    
                Console.WriteLine(((IBookService)pro.Services_ChineseBook).GetBookName());
            }
            Console.Read();
        }
        private void Compose()
        {
    
    
            //创建一个程序集目录,用于从一个程序集获取所有的组件定义
            AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            //创建容器
            CompositionContainer container = new CompositionContainer(catalog);
            //直接通过契约名获取Export
            Services_MathBook = container.GetExportedValue<object>("ContractName_MathBook");
            Services_ChineseBook = container.GetExportedValue<object>("ContractName_ChineseBook");
        }
    }
}

总结

依赖倒置原则:高层模板不应该依赖于底层模板,两者应该依赖于抽象,而抽象不应该依赖于细节。

扫描二维码关注公众号,回复: 16638431 查看本文章

猜你喜欢

转载自blog.csdn.net/Aflashstar/article/details/129096763