• MEF初体验之二:定义组合部件和契约


    组合部件

    在MEF中,一个组合部件就是一个组合单元,组合部件"出口"其它组合部件需要的服务并且从其它部件"进口"需要的服务。在MEF编程模型中,为了声明组合部件的"出口"和"进口",使用的是ExportAttribute和ImportAttribute。一个组合部件至少应该包含一个[Export]。组合部件既可以被显式的添加到Container,也可以通过使用Catalogs来创建。MEF附带的默认的Catalogs是通过[Export]来识别组合部件的。

    契约

    组合部件并不直接依赖另一个组合部件,而是依赖一个由字符串标识的契约。每一个[Export]都有一个契约,每一个[Import]都声明了它需要的契约。Container使用契约来Import部件匹配Export组件。如果未指定契约,MEF将隐式地将类型的全限定名作为契约。如果被传递的是一个类型,也将采用上面的方式。

    注意:默认是传递一个type而不是一个字符串。尽管契约可以是任意的字符串,但是这可能会导致歧义。例如,一个名为"Sender"的契约可能会和另一个类库的名为"Sender"的契约重叠。处于这样的原因,如果你需要指定一个字符串契约,建议使用包含公司名称的命名空间来限定,例如 "Contoso.Exports.Sender"

    在下面的code snippet中,所有的export契约都是等价的。

        [Export]
        class Exporter { }
        [Export(typeof(Exporter))]
        class Exporter1 { }
        [Export("PartsAndContracts.Exporter")]
        class Exporter2 { }

    接口/抽象契约

    一个通用的模式是为一个组合部件export一个接口或者一个抽象类型的契约而不是一个具体的类型。这允许import组件完全不耦合于将要import的export组件的具体实现,从而导致关注点的分离。例如,下面你可以看到有两个都export了IMessageSender接口的Sender实现。这个Notifier类import一个IMessageSender类型的集合,我们调用分别调用每一个的Send()方法。现在一个的message senders可以很容易地被添加到系统中。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace PartsAndContracts
    {
        class Program
        {
            
            static void Main(string[] args)
            {
                Program p = new Program();
                Notifier noter = new Notifier();
                var container = new CompositionContainer();
                container.ComposeParts(noter, new EmailSender(), new TcpSender(),new PhoneSender());
                noter.Notify("Hi,MEF");
                Console.WriteLine("-----------------");
                noter.MessageSender.Send("Hi,MEF");
                Console.ReadKey();
            }
        }
        class Notifier
        {
            [ImportMany]
            public IEnumerable<IMessageSender> Senders { get; set; }
            [Import("PhoneSender")]
            public IMessageSender MessageSender { get; set; }
            public void Notify(string msg)
            {
                foreach (var item in Senders)
                {
                    item.Send(msg);
                }
            }
        }
        interface IMessageSender
        {
            void Send(string msg);
        }
        [Export(typeof(IMessageSender))]
        class EmailSender : IMessageSender
        {
            public void Send(string msg)
            {
                Console.WriteLine("Email Sent:"+msg);
            }
        }
        [Export(typeof(IMessageSender))]
        class TcpSender : IMessageSender
        {
            public void Send(string msg)
            {
                Console.WriteLine("TCP Sent:"+msg);
            }
        }
        [Export("PhoneSender",typeof(IMessageSender))]
        class PhoneSender : IMessageSender
        {
            public void Send(string msg)
            {
                Console.WriteLine("Phone Sent:" + msg);
            }
        }
    }

    如图显示:

    在上面例子中,组合部件通过type契约使得export的EmailSender和TcpSender实例import到Senders属性,通过string identifier契约使得PhoneSender部件和MessageSender匹配。

  • 相关阅读:
    Android 交错 GridView
    Android 从 Android 本地图库选择多个图片
    Android 布局管理器
    Android 高级 Jackson Marshalling(serialize)/Unmarshalling(deserialize)
    Android 基本 Jackson Marshalling(serialize)/Unmarshalling(deserialize)
    Android Jackson 概述
    Andorid 翻书效果
    Android 原生 Android ActionBar Tab (滑动)导航
    Android 原生 Android ActionBar
    Android 关于操作栏 ActionBar 的设计原则【转载+整理】
  • 原文地址:https://www.cnblogs.com/jellochen/p/3660479.html
Copyright © 2020-2023  润新知