ray abu
ray abu

Reputation: 143

Can't Inject dependency for List<t> as constructor argument using Unity

I'm using Unity to instantiate my MenuRepository instance. I'm getting the following error when trying to do so..

The type list`1 has multiple constructors of length 1. unable to disambiguate.

I've tried the following registration, but with no luck..

container.RegisterType<IMenuRepository, MenuRepository>(
    new PerThreadLifetimeManager(), 
    new InjectionConstructor(typeof(IMonopolyEntitiesDbContext), 
    typeof(List<MenuLink>)));

Here's my registration

container.RegisterType<MenuLink>();
container.RegisterType <List<MenuLink>>();
container.RegisterType<IMonopolyEntitiesDbContext, MonopolyEntities>(
    new PerThreadLifetimeManager());
container.RegisterType<IMenuRepository, MenuRepository>(
    new PerThreadLifetimeManager(), 
    new InjectionConstructor(typeof(IMonopolyEntitiesDbContext), typeof(List<MenuLink>)));

MenuRepository

public class MenuRepository : IMenuRepository
{
    IMonopolyEntitiesDbContext _dbContext;
    List<MenuLink> _allsubMenus;

    public MenuRepository(IMonopolyEntitiesDbContext context, List<MenuLink> allsubMenus)
    {
        _dbContext = context;
        _allsubMenus = allsubMenus;
    }
}

Upvotes: 0

Views: 868

Answers (2)

Legends
Legends

Reputation: 22672

I used InjectionConstructor with no parameters.

using (var c = new UnityContainer())
{
    c.RegisterType(typeof(List<string>), new InjectionConstructor());
    c.RegisterType<IMyParamClass, MyParamClass>();

    c.RegisterType<IMyClass, MyClass>(
                    new PerThreadLifetimeManager(),
                    new InjectionConstructor(typeof(IMyParamClass),
                    typeof(List<string>)));

    var obj = c.Resolve<IMyClass>();
    obj.write();
}

.

Upvotes: 3

Steven
Steven

Reputation: 172646

You need to understand that the goal of an IoC container is to map abstractions to implementations and to build up object graphs from that. So to be able to create objects, Unity needs to know how to create objects. List<T> however, is not your typical service type. It has multiple constructors and Unity has therefore no clue of how to create this type.

But even if it did know how to create it (for instance by using the default constructor of List<T>), this still would be rather useless to you, because in that case an empty list would be injected into consumers. That's hardly ever useful, at all.

So the least you should do is exactly specify what to inject. For instance by doing this:

container.RegisterInstance<List<MenuLink>>(new List<MenuLink>
{
    new MenuLink { Id = 1, Name = "foo" },
    new MenuLink { Id = 2, Name = "bar" },
    new MenuLink { Id = 3, Name = "foobar" },
});

This will work for you, since you stated that the List<MenuLink> is practically a singleton and is not populated from the database. However, registering this List<MenuLink> in your container would still be problematic, because this List<T> can now be injected into any consumer, while you should never do this. This List<MenuLink> is an implementation detail of the MenuRepository that is probably responsible of updating it. Injecting the List<MenuLink> into other consumers is risky, because List<T> is not thread-safe. It's best to keep this List<T> internal to the MenuRepository, so it can do the proper locking.

So instead of registering the List<MenuLink> in the container, register the repository with the list explicitly as follows:

var menuLinks = new List<MenuLink>
{
    new MenuLink { Id = 1, Name = "foo" },
    new MenuLink { Id = 2, Name = "bar" },
    new MenuLink { Id = 3, Name = "foobar" },
};

container.RegisterType<IMenuRepository, MenuRepository>(
    new PerThreadLifetimeManager(), 
    new ParameterOverride("allsubMenus", menuLinks));

Upvotes: 3

Related Questions