Resolve / Inject Enumerable of Registered Open Generics

Jan 7, 2015 at 4:33 PM
I'm building a plugin system for my project. The marker interface for the plugin is generic, and includes the return type for the method. I'm successfully discovering and Registering all of my plugins using RegisterAllForOpenGeneric, but I'm having trouble getting those registrations back out.

I need to find all of the plugins that are registered, and then invoke a method on them. Since I don't know the generic type until runtime, I'm having trouble formulating the correct command to pull them out of the container in a generic manner.

Any ideas appreciated.

Thanks,

Mike

Very Generic Sample Code is below:

Registration
    _container.RegisterAllOpenGeneric(typeof(IPlugin<>));
Interface:
public interface IPlugin<T> {
    T Run();
}
Implementations:
public class ComputerInfoPlugin : IPlugin<ComputerInfo> {
    public ComputerInfo Run(){
        return new ComputerInfo();
    }
}

public class SomeOtherPlugin : IPlugin<SomeOtherInfo> {
    public SomeOtherInfo Run(){
        return new SomeOtherInfo();
    }
}
Coordinator
Feb 2, 2015 at 7:32 PM
Edited Feb 13, 2015 at 10:29 AM
The registration depends on whether there is a one-to-one mapping between a closed version of IPlugin<T> and an implementation or whether there are possible multiple implementations for the same closed generic version of IPlugin<T>. For instance, do you have multiple plugins that implement IPlugin<ComputerInfo>? If that's the case, you need a one-to-many mapping (a registration of a collection) and need to resolve collections.

In case there is a one-to-one mapping, you need the following registration:
// This makes one-to-one mappings.
container.RegisterManyForOpenGeneric(typeof(IPlugin<>), listOfAssemblies);

// Resolve exactly one, because that's what we registered.
var plugin = container.GetInstance<IPlugin<ComputerInfo>>();
If, on the other hand, you have possibly multiple registrations per closed-generic version, you need this:
// This registers collections of implementations by their closed generic abstraction:
container.RegisterManyForOpenGeneric(typeof(IPlugin<>), container.RegisterAll, 
    listOfAssemblies);

// Resolve a collection.
var plugins = container.GetAllInstances<IPlugin<ComputerInfo>>();

// Or inject it into the constructor either as an IEnumerable<IPlugin<ComputerInfo>>,
// ReadOnlyCollection<IPlugin<ComputerInfo>> or ReadOnlyList<IPlugin<ComputerInfo>>.
The RegisterAllOpenGeneric method that you use is for registering collections that consist solely of open-generic implementations. Due to changes in Simple Injector 2.6 however, the method has become redundant. Everything you can do with RegisterAllOpenGeneric can now also be done with RegisterAll, but the use of RegisterAll is advised. RegisterAllOpenGeneric will be marked obsolete in a future version and will likely be removed in v3.0.