Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity: Register and resolve class with generic type

I'm using Unity and try to follow to SOLID-principles as far as possible. Therefore all implementations only have dependencies to interfaces.

I have a collectionwrapper which looks like this:

public interface ICollectionWrapper<TModel>
{
    int TotalCount { get; set; }
    IEnumerable<TModel> Items { get; set; }
}

Now I want to create the instance of ICollectionFactory<T> with a factory. This is what I got so far:

public interface ICollectionWrapperFactory
{
    ICollectionWrapper<T> CreateCollection<T>();
    ICollectionWrapper<T> CreateCollection<T>(IEnumerable<T> items);
    ICollectionWrapper<T> CreateCollection<T>(IEnumerable<T> items, int totalCount);
}

public class CollectionWrapperFactory : ICollectionWrapperFactory
{
    private readonly IUnityContainer _container;

    public CollectionWrapperFactory(IUnityContainer container)
    {
        _container = container;
    }

    public ICollectionWrapper<T> CreateCollection<T>()
    {
        var collectionWrapper = _container.Resolve<ICollectionWrapper<T>>();
        return collectionWrapper;
    }

    public ICollectionWrapper<T> CreateCollection<T>(IEnumerable<T> items)
    {
        throw new System.NotImplementedException();
    }

    public ICollectionWrapper<T> CreateCollection<T>(IEnumerable<T> items, int totalCount)
    {
        throw new System.NotImplementedException();
    }
}

I know that using the container as a servicelocator is considered an anti-pattern, but I don't know any better way to solve this. If there's a better pattern for doing this I'm all ears... An alternative is using the Activator, but then the factory would need to know about the actual implementation of ICollectionWrapper<T>.

But the real problem is that I cannot register the ICollectionWrapper correctly.

container.RegisterType<ICollectionWrapper<T>, CollectionWrapper<T>>(new TransientLifetimeManager()); // Does not compile.

T may be any type. I want to be able to create instances of ICollectionWrapper<T> without having to register every possible combination of T.

Currently I only have one implementation of ICollectionWrapper<T>. But the point is that I really want Unity to be the only part that knows about the actual implementation.

[DataContract]
public class CollectionWrapper<TModel> : ICollectionWrapper<TModel>
{
    public CollectionWrapper(IEnumerable<TModel> items)
    {
        Items = items;
    }

    public CollectionWrapper(IEnumerable<TModel> items, int totalCount)
    {
        Items = items;
        TotalCount = totalCount;
    }

    public CollectionWrapper()
    {

    }

    [DataMember]
    public int TotalCount { get; set; }
    [DataMember]
    public IEnumerable<TModel> Items { get; set; }
}
like image 739
smoksnes Avatar asked Feb 11 '16 08:02

smoksnes


1 Answers

T may be any type. I want to be able to create instances of ICollectionWrapper without having to register every possible combination of T.

That's what register generics is for. Some IOC name the method as RegisterGeneric to make it self explanatory (autofac for example), but unity keep it just an overload of RegisterType.

container.RegisterType(typeof(ICollectionWrapper<>), typeof(CollectionWrapper<>), new TransientLifetimeManager());

Also note that your injectable is having multiple constructors. That itself is considered as anti-pattern.

If you fix the multiple construtor thing, above registration will work.

like image 174
Sriram Sakthivel Avatar answered Nov 08 '22 13:11

Sriram Sakthivel