MEF 编程指南(六):导出和元数据

声明导出解释了部件导出服务的基础知识和价值观(Values)。有时候出于种种缘由,导出关联信息是很是必要的。一般,用于解释关于功能公共契约的具体实现。容许导入知足约束要求的导出,或者导入全部可用的实现而且在导出前在运行时检查他们的功能。html

 
为导出附加元数据(Attaching Metadata to an Export)
 
考虑到 IMessageSender 服务更早引入。假设咱们有一些实现,和相关的消费者实现(Consumer Of The Implementations)有差别。对于咱们的示例,消息的传送(Transport)和是否安全(Secure)对于消费者(导入部件)都是重要的信息。
 
 
使用 ExportMetadataAttribute 特性
 
全部咱们须要作的事情是使用 [System.ComponentModel.Composition.ExportMetadataAtrribute] 附加这些信息。
 
    [Export(typeof(IMessageSender))]
    [ExportMetadata("transport", "smtp")]
    public class EmailSender : IMessageSender
    {
        public void Send(string message)
        {
            Console.WriteLine(message);
        }
    }
 
    [Export(typeof(IMessageSender))]
    [ExportMetadata("transport", "smtp")]
    [ExportMetadata("secure", null)]
    public class SecureEmailSender : IMessageSender
    {
        public void Send(string message)
        {
            Console.WriteLine(message);
        }
    }
 
    [Export(typeof(IMessageSender))]
    [ExportMetadata("transport", "phone_network")]
    public class SMSSender : IMessageSender
    {
        public void Send(string message)
        {
            Console.WriteLine(message);
        }
    }
 
    public interface IMessageSender
    {
        void Send(string message);
    }

 

 
 
使用自定义导出特性(Using a Custom Export Attribute)
 
为了使用比 ExportMetadata 更强类型,须要建立自定义特性而且用 [System.ComponentModel.Composition.MetadataAttribute] 标识。本例中也继承自 ExportAttribute 特性,于是建立自定义导出特性而且指定了元数据。
 
 
    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
    public class MessageSenderAttribute : ExportAttribute
    {
        public MessageSenderAttribute() : base(typeof(IMessageSender)) { }
        public MessageTransport Transport { get; set; }
        public bool IsSecure { get; set; }
    }
 
    public enum MessageTransport
    {
        Undefined,
        Smtp,
        PhoneNetwork,
        Other
    }
 
    public interface IMessageSender
    {
        void Send(string message);
    }

 

 
以上,MetadataAttribute 应用于自定义导出特性。下一步是将特性应用 IMessageSender 实现:
 
    [MessageSender(Transport=MessageTransport.Smtp)]
    public class EmailSender : IMessageSender
    {
        public void Send(string message)
        {
            Console.WriteLine(message);
        }
    }
 
    [MessageSender(Transport=MessageTransport.Smtp, IsSecure=true)]
    public class SecureEmailSender : IMessageSender
    {
        public void Send(string message)
        {
            Console.WriteLine(message);
        }
    }
 
    [MessageSender(Transport=MessageTransport.PhoneNetwork)]
    public class SMSSender : IMessageSender
    {
        public void Send(string message)
        {
            Console.WriteLine(message);
        }
    }

 

 

这就是在导出端须要作的所有事情。MEF 机制下依然会填充一个字典(Populating A Dictionary),可是这对用户不可见。
 
注意:你也能够建立没有自身导出的元数据特性,经过建立一个使用 MetadataAttribute 标识的特性。在这些状况下,元数据会被添加到有相同成员的应用自定义元数据特性的导出。
 
 
导入元数据(Importing Metadata)
 
导入部件能访问附加到导出的元数据。
 
 
使用强类型元数据(Using Strongly-typed Metadata)
 
 
为了访问强类型的元数据,经过定义匹配只读属性(名称和类型)的接口建立元数据视图。对于咱们示例,像下面的接口:
 
    public interface IMessageSenderCapabilities
    {
        MessageTransport Transport { get; }
        bool IsSecure { get; }
    }

 

 
而后,就可使用 System.Lazy<T, TMetadata> 类型开始导入,其中 T 是契约类型,TMetadata 是建立的接口。
 
 
    public class HttpServerHealthMonitor
    {
        [ImportMany]
        public Lazy<IMessageSender, IMessageSenderCapabilities>[] Senders { get; set; }
 
        public void SendNotification()
        {
            Compose();
            foreach (var sender in Senders)
            {
                if (sender.Metadata.Transport == MessageTransport.Smtp && sender.Metadata.IsSecure)
                {
                    var messageSender = sender.Value;
                    messageSender.Send("Server is fine");
 
                    break;
                }
            }
        }
 
        private void Compose()
        {
            //var container = new CompositionContainer();
            //container.ComposeParts(this, new EmailSender());
            AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
        }
    }

 

使用弱类型元数据(Using Weakly-Typed Metadata)
 
为了用弱类型的方式访问元数据,使用 System.Lazy<T, TMetadata> 类型传递 IDictionary<string, object> 元数据给导入。而后,能够经过 Dictionary 的元数据属性访问元数据。
 
注意:一般,咱们建议经过强类型方法访问元数据,而后有些系统须要容许以动态形式访问元数据。
 
 
    public class HttpServerHealthMonitor
    {
        [ImportMany]
        public Lazy<IMessageSender, IDictionary<string, object>>[] Senders { get; set; }
 
        public void SendNotification()
        {
            Compose();
 
            foreach (var sender in Senders)
            {
                if (sender.Metadata.ContainsKey("Transport"))
                {
                    var messageSender = sender.Value;
                    messageSender.Send("Server is fine");
                }
            }
        }
 
        private void Compose()
        {
            //var container = new CompositionContainer();
            //container.ComposeParts(this, new EmailSender());
            AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
        }
    }

 

 
元数据过滤和 DefaultValueAttribute 特性(Metadata Filtering and DefaultValueAttribute)
 
 
当指定元数据视图(Metadata View)的时候,隐式过滤将会匹配那些在视图定义中知足包含元数据属性条件的导出。你可使用 System.ComponentModel.DefaultValueAttribute 特性指定一个元数据视图是非必要的,下面你能够看到,咱们在 IsSecure 上指定默认值(Default Value)为假(False)。这意味着,若是一个部件导出 IMessageSender,可是没有提供 IsSecure 元数据,也仍将被匹配。
 
    public interface IMessageSenderCapabilities
    {
        MessageTransport Transport { get; }
        [DefaultValue(false)]
        bool IsSecure { get; }
    }

 

 
原文地址:
相关文章
相关标签/搜索