Reputation: 1805
In my implementation, I need to dynamically resolve a service, based on the servicekey. Therefor, I want to pass a Func, but can't get that working. Any help on this is appreciated.
Let's have the following implemention:
public interface IMyInterface {
void Foo();
}
public class ClassA : IMyInterface {
void Foo() => BarA();
}
public class ClassB : IMyInterface {
void Foo() => BarB();
}
public class ClassC : IOtherInterface {
private readonly Func<string, IMyInterface> getInstance_;
void ClassC(Func<string, IMyInterface> getInstance)
{
getInstance_ = getInstance;
}
void SomeLogic()
{
IMyInterface implementation = getInstance("keyA");
implementation.Foo();
}
}
public static void Main()
{
var c = new Container();
c.Register<IMyInterface, ClassA>(serviceKey:"keyA");
c.Register<IMyInterface, ClassB>(serviceKey:"keyB");
c.Register<IOtherInterface, ClassC>();
c.Resolve<IOtherInterface>();
}
The last call fails, which I understand. The exception thrown is:
DryIoc.ContainerException: 'Unable to resolve IMyInterface with passed arguments [_String0] IsWrappedInFunc, IsDirectlyWrappedInFunc
in wrapper Func<String, IMyInterface> FactoryId=10 with passed arguments [_String0] IsResolutionCall
from Container with Scope {no name}
with Rules with {TrackingDisposableTransients} and without {ThrowOnRegisteringDisposableTransient}
with normal and dynamic registrations:
("keyA", {FactoryID=32, ImplType=ClassA}) ("keyB", {FactoryID=33, ImplType=ClassB}) '
I figured out how to register this with a Delegate:
c.RegisterDelegate<Func<string, IMyInterface>>(r => (key) => c.Resolve<IMyInterface>(key));
But in the documentation, DryIoc recommends using factory-methods above Delegates. I've played a lot with Made.Of-notations (which I find poorly documented), but have not found a working one.
Is this possible with a (static) Factory-method?
Upvotes: 0
Views: 2116
Reputation: 4950
If you need to dynamically select the service based on the key but without relying on Service Locator anti-pattern (without injecting the IResolver
into ClassC
) -
you may inject all available service factories as described here https://github.com/dadhi/DryIoc/blob/master/docs/DryIoc.Docs/RegisterResolve.md#keyed-registrations in the second example:
public class ClassC : IOtherInterface {
private readonly Func<string, IMyInterface> _implementations;
void ClassC(KeyValuePair<string, Func<IMyInterface>>[] implementations)
{
_implementations = implementations;
}
void SomeLogic()
{
var implementationFactory = _implementations.First(x => x.Key == "keyA").Value;
var implementation = implementationFactory();
implementation.Foo();
}
}
BTW, The same approach is taken in Autofac and maybe by other DI containers capable to compose the wrappers like Func
, Lazy
and the collections.
BTW2, If you don't like the KeyValuePair
you may use Tuple
instead.
Upvotes: 2