Walkingsteak
Walkingsteak

Reputation: 349

Composing an instance of a class for each concrete implementation of an interface which that class has as a dependency

Was unsure how to make a sensible title for this post.

Say I have a class

[Export(typeof(IMessageSender))]
public class MessageSender : IMessageSender
{
    private IMessagingInterface _messagingInterface;
    private IEventAggregator _eventAggregator;

    [ImportingConstructor]
    public MessageSender(IMessagingInterface messagingInterface, IEventAggregator eventAggregator)
    {
        _messagingInterface = messagingInterface;
        _eventAggregator = eventAggregator;
    }

    public void SendMessage(string message)
    {
        _messagingInterface.Write(message);
    }

    public InterfaceStatus GetStatus()
    {
        return _messagingInterface.Status;
    }

    ...
    etc. Many methods in this class.
}

and I have several different IMessagingInterface, such as

[Export(typeof(IMessagingInterface))]
public SerialPortInterface : IMessagingInterface
{
    ..
}

[Export(typeof(IMessagingInterface))]
public UdpInterface : IMessagingInterface
{
    ..
}
etc

In my application, I currently instantiate the different parts like this at the startup of my application:

eventAggregator = new EventAggregator();
batch.AddExportedValue<IMessageSender>("SerialPortSender", new MessageSender(new SerialPortInterface(), eventAggregator);
batch.AddExportedValue<IMessageSender>("UdpSender", new MessageSender(new UdpInterface (), eventAggregator);
... 
etc for the rest 

Then I can specify which one I want injected elsewhere by using the contract name.

However, I feel like doing this composition myself in the bootstrapper and creating instances with new is wrong and unnecessary, but I haven't found a way to do it differently.

Upvotes: 0

Views: 182

Answers (2)

Sander Aernouts
Sander Aernouts

Reputation: 979

Have a look at this post: Getting all types that implement an interface

And then use Activator.CreateInstance(...) to construct the instances (see: https://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx)

Something like this should do it:

eventAggregator = new EventAggregator();
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(s => s.GetTypes())
    .Where(p => type.IsAssignableFrom(p));

foreach (var t in types)
{
    var instance = (IMyInteface)Activator.CreateInstance(t);
    batch.AddExportedValue<IMessageSender>(t.Name, new MessageSender(instance, eventAggregator);
}

As Tchi Yuan pointed out, using a IOC framework is also an option such as:

These will handle the scanning of assemblies and instance creation for you according to the configurations you provide.

Upvotes: 1

TchiYuan
TchiYuan

Reputation: 4278

I've had this problem in the past and what I did is that I used Microsoft Unity in conjuncture with MEF and then simply pass your unity container to your MEF extension/plugin constructor. Registering and resolving named dependencies with Unity is trivial.

Upvotes: 1

Related Questions