I want to register multiple instances of a class in a container. Each instance is identified by its ID property.
public interface MyInterface
{
string Id { get; }
}
public class MyImpl : MyInterface
{
public string Id { get; }
public MyImpl(string id) => Id = id;
}
And, I want to receive this instance in the constructor of another class.
using DryIoc;
public class User
{
public MyInterface Obj { get; }
public User(string id, Func<string, MyInterface> getObj)
=> Obj = getObj(id);
}
class Program
{
static void Main()
{
Container container = new();
container.RegisterInstance<MyInterface>(new MyImpl("A"), serviceKey: "A");
container.RegisterInstance<MyInterface>(new MyImpl("B"), serviceKey: "B");
container.Register<User>();
var user = container.Resolve<Func<string, User>>()("A");
}
}
This code throws ContainerException.
DryIoc.ContainerException: code: Error.UnableToResolveFromRegisteredServices;
message: Unable to resolve MyInterface with passed arguments [String@0] (IsWrappedInFunc, IsDirectlyWrappedInFunc)
in wrapper Func<String, MyInterface> as parameter "getObj" WrapperExpressionFactoryWithSetup FactoryId=158 with passed arguments [String@0] (IsWrappedInFunc)
in User FactoryId=146 with passed arguments [String@0] (IsWrappedInFunc, IsDirectlyWrappedInFunc)
in resolution root wrapper System.Func`2[System.String,User] WrapperExpressionFactoryWithSetup FactoryId=158 with passed arguments [String@0]
from container without scope
with normal and dynamic registrations:
("B", {FactoryID=145, ImplType=MyImpl, Reuse=Singleton {Lifespan=1000}}) ("A", {FactoryID=144, ImplType=MyImpl, Reuse=Singleton {Lifespan=1000}})
The desired instance can be obtained by specifying the serviceKey in Container.Resolve(). However, since the User class is constructor-injected into another instance, we do not want to call Contaienr's methods directly.
I think that I can specify made appropriately in the argument of Register(). How should I specify it?
Edit
For now, create an object holder and work around the problem.
public static class Holder<T> where T : class
{
private static readonly Dictionary<string, T> _dictionary = new();
public static void Add(string id, T obj) => _dictionary.Add(id, obj);
public static void Remove(string id) => _dictionary.Remove(id);
public static T Get(string id) => _dictionary[id];
}
interface IService
{
string Id { get; }
}
class Service : IService
{
public string Id { get; }
public Service(string id) => Id = id;
}
interface IServiceUser
{
IService Service { get; }
}
class ServiceUser : IServiceUser
{
public IService Service { get; }
public ServiceUser(IService service) => Service = service;
}
class ViewModel
{
public ViewModel(IServiceUser serviceUser)
{
Console.WriteLine(serviceUser.Service.Id);
}
}
static class Program
{
static void Main()
{
Holder<IService>.Add("A", new Service("A"));
Holder<IService>.Add("B", new Service("B"));
Container container = new();
container.Register(made: Made.Of(() => Holder<IService>.Get(Arg.Of<string>())));
container.Register<IServiceUser, ServiceUser>();
container.Register<ViewModel>();
var createVm = container.Resolve<Func<string, ViewModel>>();
var vmA = createVm("A");
var vmB = createVm("B");
}
}
But since container can hold objects, I am thinking that if I can transfer the value passed in Func to serviceKey, there is no need for Holder class.