Reputation: 5736
I'm trying to set up a container to register a class that takes in its constructor a IDictionary<string, IInterface>
so in my IoC I would like to know how to get a named instance (if that feature is available in SI). An example of what I want to achieve is:
container.Register<IOtherInterface>(() =>
new OtherInterface(new Dictionary<string, IInterface>
{
{ "a", container.GetInstance<IInterface>("named-a") },
{ "b", container.GetInstance<IInterface>("named-b") },
});
Is there any way to configure this?
Updated:
The implementation of the interface is the same object with different parameters and that's an example I haven't been able to see in the SI documentation https://simpleinjector.readthedocs.io/en/latest/howto.html#resolve-instances-by-key . I'd like to avoid the fact that I have to instantiate a new Interface(..with the relevant parameters...) for each value in the dictionary that's why I thought that naming a registration was something available in SI.
Maybe my approach is wrong and I should try to establish the dependencies in a different way.
Example of usage:
public class OtherInterface : IOtherInterface
{
private readonly IDictionary<string, IInterface> _interfces;
public OtherInterface(IDictionary<string, IInterface> interfaces)
{
_interfaces = interfaces;
}
public void DoSomething(MyRequest request)
{
if(_interfaces.ContainKey(request.SelectMyInterface))
{
_interfaces[request.SelectMyInterface].DoSpecificStuff();
}
}
}
I could potentially extend the interface IInterface and apply the strategy pattern here having a method like Applies(string type)
but I have used the dictionary approach in the past with Ninject.
Upvotes: 0
Views: 1028
Reputation: 172646
Keyed registrations are done in Simple Injector by creating InstanceProducer
instances 'manually' as follows:
var a = Lifestyle.Transient.CreateProducer<IInterface, A>(container);
var b = Lifestyle.Transient.CreateProducer<IInterface, B>(container);
Using these instance producers, you can make the dictionary registration as follows:
container.Register<Dictionary<string, IInterface>(() => new Dictionary<string, IInterface>
{
{ "a", a.GetInstance() },
{ "b", b.GetInstance() },
});
Your OtherInterface
looks like a dispatcher to me. If it's only job is to route an incoming request, I would say that's okay.
But instead of injecting a dictionary with a complete list of created instances, I would like to propose a bit different design:
public class OtherInterface : IOtherInterface
{
private readonly IDictionary<string, Func<IInterface>> _interfces;
public OtherInterface(IDictionary<string, Func<IInterface>> interfaces) {
_interfaces = interfaces;
}
public void DoSomething(MyRequest request) =>
_interfaces[request.SelectMyInterface].Invoke().DoSpecificStuff();
}
Here the dictionary contains a Func<IInterface>
. This way an implementation can be created on the fly, without having to create all implementations on every call.
You can register this as follows:
container.RegisterSingleton<IOtherInterface>(new OtherInterface(
new Dictionary<string, Func<IInterface>>
{
{ "a", CreateProducer<A>() },
{ "b", CreateProducer<B>() },
});
private Func<IInterface> CreateProducer<T>() where T : IInterface =>
Lifestyle.Transient.CreateProducer<IInterface, T>(this.container).GetInstance;
Alternatively, you might benefit from a design as described here (and explained in more detail here), although it's a bit hard to tell with the limited amount of context given by your question.
Upvotes: 1