I have the following registrations prior to the one my question is about:
container.Register<ISettings>();
container.Register<Connection1>();
container.Register<Connection2>();
Connection1
and Connection2
both implement an the interface IConnection
. To simplify my case ISettings
just contains a property UseConnection1
.
What I want is to register a mapping or delegate for service type IConnection
that expects ISettings
as a dependency and returns either Connection1
or Connection2
as its implementation type.
RegisterMapping
itself does not have such capabilities due to the fact, that one can't use any depending services to specify the mapping dynamically.
RegisterDelegate
on the other hand has the capabilities to get a specific depending service, but expects the user to return the implementation itself, not its type, like that:
container.RegisterDelegate<ISettings, IResolver, IConnection>((settings, resolver) =>
{
var serviceType = settings.UseConnection1 ? typeof(Connection1) : typeof(Connection2);
return resolver.Resolve<IConnection>(serviceType);
});
As seen, that implementation would be got from the IResolver
which is far from perfect, as described in the DryIoc wiki.
What I wish to do is something like this:
container.RegisterSomething<IConnection>((ISettings settings) => settings.UseConnection1 ? typeof(Connection1) : typeof(Connection2));
Is this possible in any way with DryIoc?
First, I agree with @steven that the runtime data should be treated with care and better be solved outside of DI. Especially, if it is mutable and being used as a condition.
Second, if unavoidable, I would've used the factory delegate from the comments as the least surprise solution: RegisterDelegate<ISettting, IConnection>(settings => /*connection construction*/)
.
Last, the heads-on answer would be the condition-based resolution and can be done with the condition setup:
using System;
using DryIoc;
public class Program
{
public static void Main()
{
var container = new Container();
container.Register<ISettings, Settings>(Reuse.Singleton);
container.Register<IConnection, Connection1>(setup: Setup.With(condition: r => r.Container.Resolve<ISettings>().UseConnection1));
container.Register<IConnection, Connection2>(setup: Setup.With(condition: r => r.Container.Resolve<ISettings>().UseConnection1 == false));
var settings = container.Resolve<ISettings>();
settings.UseConnection1 = true;
var conn1 = container.Resolve<IConnection>();
Console.WriteLine(conn1.GetType());
settings.UseConnection1 = false;
var conn2 = container.Resolve<IConnection>();
Console.WriteLine(conn2.GetType());
}
public interface ISettings
{
bool UseConnection1 { get; set; }
}
public class Settings : ISettings { public bool UseConnection1 { get; set; } }
public interface IConnection {}
public class Connection1 : IConnection {}
public class Connection2 : IConnection {}
}
There is another option closer to what you have originally imagined:
container.Register<IConnection>(made: Made.Of(r =>
r.Container.Resolve<ISettings>().UseConnection1 ? typeof(Connection1) : typeof(Connection2)));