Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity register generic type for non generic interface

my scenario looks (to me) very straight forward, but I couldn't find a resolution.

I have this scenario

public class Class<T> : IInterface where T : class
{ 

}

the interface cannot be made generic (coming from WCF lib.)

so I want to register the interface like this

container.RegisterType(typeof (IInterface ), typeof (Class<>));

and then resolve it with T

How can I do it? What am I missing?

my intention is doing something like

container.Resolve<IInterface>(/* specify T */);
like image 1000
Tom Avatar asked Dec 05 '22 09:12

Tom


2 Answers

If you don't need to resolve using the uncontrolled interface, you can make your own controlled interface which uses generics and derives from the uncontrolled interface. Then you can register the open generic and resolve the closed generic types.

public interface IControlled<T> : IUncontrolled {}
public class Controlled<T> : IControlled<T> {}

container.RegisterType(typeof(IControlled<>), typeof(Controlled<>));

IUncontrolled instance = container.Resolve<IControlled<string>>();
like image 76
TylerOhlsen Avatar answered Dec 06 '22 23:12

TylerOhlsen


What am I missing?

You are missing a factory.

Think about it, there are no magic leprechauns working on the background guessing the type you need. You need to supply it. Either by explicitly stating what T is while configuring like this:

container.RegisterType(
    typeof(IInterface),
    typeof(Class<SomeType>));

Or by creating a factory where you pass on the T at runtime:

public interface IInterfaceFactory
{
    IInterface Create<T>();
}

The factory can be registered as follows:

container.RegisterInstance<IInterfaceFactory>(
    new InterfaceFactory(container));

And an implementation can look as follows:

public class InterfaceFactory : IInterfaceFactory
{
    private readonly IUnityContainer container;
    public InterfaceFactory(IUnityContainer container)
    {
        this.container = container;
    }

    public IInterface Create<T>()
    {
        return this.container.Resolve<Class<T>>();
    }
}

Now you can inject the IInterfaceFactory into consumers that need to work with IInterface and they can request the version they need by calling the Create<T>() method.

UPDATE

If you think this is too much code, you can also register a factory delegate as follows:

container.RegisterInstance<Func<Type, IInterface>>(
    type => container.Resolve(
        typeof(Class<>).MakeGenericType(type)));

This is basically the same, but now inlined in a delegate. Your consumers can now depend on a Func<Type, IInterface> instead of a IInterfaceFactory and pass a type instance on to the delegate.

I personally prefer the use of a descriptive interface such as IInterfaceFactory. It's up to you.

like image 25
Steven Avatar answered Dec 06 '22 21:12

Steven