Getting only necessary plugins with MEF in .NET

限于喜欢 提交于 2019-12-02 17:21:12
Matthew Abbott

MEF supports the exporting of custom metadata to accompany your exported types. What you need to do, is first define an interface that MEF will use to create a proxy object containing your metadata. In your example, you'll likely need a unique name for each export, so we could define:

public interface INameMetadata
{
  string Name { get; }
}

What you would then need to do, is make sure you assign that metadata for each of your exports that require it:

[Export(typeof(IMessageSender)), ExportMetadata("Name", "EmailSender1")]
public class EmailSender : IMessageSender
{
  public void Send(string message)
  {
    Console.WriteLine(message);
  }
}

What MEF will do, is generate a project an implementation of your interface, INameMetadata using the value stored in the ExportMetadata("Name", "EmailSender1") atrribute.

After you've done that, you can do a little filtering, so redefine your [Import] to something like:

[ImportMany]
public IEnumerable<Lazy<IMessageSender, INameMetadata>> Senders { get; set; }

What MEF will create is an enumerable of Lazy<T, TMetadata> instances which support deferred instantiation of your instance type. We can query as:

public IMessageSender GetMessageSender(string name)
{
  return Senders
    .Where(l => l.Metadata.Name.Equals(name))
    .Select(l => l.Value)
    .FirstOrDefault();
}

Running this with an argument of "EmailSender1" for the name parameter will result in our instance of EmailSender being returned. The important thing to note is how we've selected a specific instance to use, based on querying the metadata associated with the type.

You can go one further, and you could amalgamate the Export and ExportMetadata attributes into a single attribute, such like:

[AttributeUsage(AttributeTargets.Class, AllowMultiple=false), MetadataAttribute]
public class ExportMessageSenderAttribute : ExportAttribute, INameMetadata
{
  public ExportMessageSenderAttribute(string name)
    : base(typeof(IMessageSender))
  {
    Name = name;
  }

  public string Name { get; private set; }
}

This allows us to use a single attribute to export a type, whilst still providing additional metadata:

[ExportMessageSender("EmailSender2")]
public class EmailSender : IMessageSender
{
  public void Send(string message)
  {
    Console.WriteLine(message);
  }
}

Obviously querying this way presents you with a design decision. Using Lazy<T, TMetadata> instances means that you'll be able to defer instantiation of the instance, but that does mean that only one instance can be created per lazy. The Silverlight variant of the MEF framework also supports the ExportFactory<T, TMetadata> type, which allows you to spin up new instances of T each time, whilist still providing you with the rich metadata mechanism.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!