MEF初体验之四:Imports声明

组合部件使用[System.ComponentModel.Composition.ImportAttribute]特性声明导入。与导出类似,也有几种成员支持,即为字段、属性和构造器参数。同样,我们也来看下该特性类的声明:

[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field 
| AttributeTargets.Property, AllowMultiple=false, Inherited=false)] public class ImportAttribute : Attribute, IAttributedImport { }

果然,支持这三种成员(这里Parameter而不是GenericParameter),也不支持继承,另外,与[Export]不同的是,在同一个目标上不能应用多次该特性

属性倒入

为了向属性导入一个值,用[Import]来声明该属性。这是我们在前面的例子中使用的。例如下面倒入一个IMessageSender的代码片段:

[Import]
public IMessageSender MessageSender { get; set; }

构造函数参数

你也可以指定构造函数参数导入。这意味着你是将构造函数参数添加各自的导入,而不是将属性添加各自的导入。为了使用它,按照下面的步骤:

  1. 添加一个[System.ComponentModel.Composition.ImportingConstructorAttribute]特性到应该被MEF使用的构造函数上。
  2. 为构造函数参数添加各自的导入

例如,下面的代码在Program类构造函数上导入一个message sender。

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ImportsDeclaring
{
    class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            p.Run();
            Console.ReadKey();
        }
        void Run()
        {
            var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var container = new CompositionContainer(catalog);
            container.ComposeExportedValue<IMessageSender>(new EmailSender());
            var s = container.GetExportedValue<IService>();
            s.Work();
        }
    }
    [Export(typeof(IService))]
    class SenderService:IService
    {
        private IMessageSender sender;
        [ImportingConstructor]
        public SenderService([Import(AllowDefault = true)]IMessageSender sender)
        {
            this.sender = sender;
        }

        void IService.Work()
        {
            if (sender != null)
                sender.Send("Hi,MEF");
        }
    }
    interface IService
    {
        void Work();
    }
    interface IMessageSender
    {
        void Send(string msg);
    }
    class EmailSender : IMessageSender
    {
        public void Send(string msg)
        {
            Console.WriteLine("Email Sent:" + msg);
        }
    }

}

 效果如图:

参数导入

在构造函数上定义导出有这么几种不同的方式:

  1. 隐式导入-容器将会默认地使用参数的类型来识别契约。
  2. 显示导入-给参数添加[Import]特性,以此来制定要导入的契约

例如下面的两种方式等价:

[ImportingConstructor]
public
SenderService(IMessageSender sender) { this.sender = sender; } [ImportingConstructor] public SenderService([Import(typeof(IMessageSender))]IMessageSender sender) { this.sender = sender; }

字段导入

MEF也支持直接将值导入到字段。形式上和属性导入很像。但是需要注意的是,私有成员(字段、属性和方法)的导入或导出仅仅支持在中/部分信任应用中,而在完全信任应用的支持上可能会有问题。

可选导入

MEF允许你指定一个可选的导入。当你启用它时,如果有可用的导出,这个容器将会提供该导出,并且设置导入为Default(T)。为了利用导入选项,在[Import]上设置AllowDefault=true。在上面我们已经使用了它,作用是当我们未执行container.ComposeExportedValue<IMessageSender>(new EmailSender()),即未给构造函数参数导入值,这时,[Import(AllowDefault=true)]相当于container.ComposeExportedValue<IMessageSender>(null),虽然参数值为null,但是契约匹配仍然生效,而如果AllowDefault=false(默认值),这时,构造器参数导入无法匹配导出,在执行下一行代码var s = container.GetExportedValue<IService>();就会报错。

导出集合

除了单个导出之外,你可以使用[ImportMany]来导出集合。这意味着指定的契约的所有实例都将被导入到这个容器。

MEF部件也支持重组。这意味着当在容器中新的导出可用时,集合会自动更新。

IPartImportsSatisfiedNotification接口

 在某些场合,当MEF在处理类的实例导入过程时,该类能得到通知,对于该类来说这可能是重要的。如果是这种情况的话,请实现IPartImportsSatisfiedNotification接口,这个接口只有一个方法:OnImportsSatisfied,当所有满足部件的导入都满足时该方法将被调用。

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 ImportsDeclaring
{
    class Example
    {
        static void Main(string[] args)
        {
            Example e = new Example();
            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:IPartImportsSatisfiedNotification
    {
        [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);
            }
        }

        public void OnImportsSatisfied()
        {
            Console.WriteLine("all imports that could be satisfied have been satisfied");
        }
    }
    [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);
        }
    }
}

效果如下:

原文地址:https://www.cnblogs.com/jellochen/p/3662268.html