I have IMessageSender interface.
using System.ComponentModel.Composition;
public interface IMessageSender
{
void Send(string message);
}
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.