Search code examples
c#dependency-injectionunity-container

Adjust Unity Dependency injection to use Lazy<T> / Func<T>


I'm working on a project that uses Unity Dependancy injection but the load performance is slowly getting worse. I am trying to adjust the code to utilise Lazy<T> (or Func<T>) so i'm trying to find a way to either register the classes with the container using Lazy<T> (or Func<T>) or have some sort of factory that could either adjust the registered types or the constructor but i am not able to seem to find a possible way to do this

At present i have numerous service classes like

public Service1(IClassLogic<GetReq, GetRes> getClass, IClassLogic<AddReq, AddRes> addClass, IClassLogic<UpdateReq, UpdateRes> updateClass, IClassLogic<DeleteReq, DeleteRes> deleteClass....){...}

then i have registrations similar to

container.RegisterType<IClassLogic<GetReq, GetRes>, GetClass>();
container.RegisterType<IClassLogic<AddReq, AddRes>, AddClass>();
container.RegisterType<IClassLogic<UpdateReq, UpdateRes>, UpdateClass>();
container.RegisterType<IClassLogic<DeleteReq, DeleteRes>, DeleteClass>();
...

Ideally i would like not to have to go an change all the signatures to

public Service1(Lazy<IClassLogic<GetReq, GetRes>> getClass, Lazy<IClassLogic<AddReq, AddRes>> addClass...

Any pointers would be greatly appreciated


Solution

  • First off some tips concerning DI in general:

    • You're right, you do not want to change the signature of the constructor. You're IoC container (Unity in your case) should enable you to design the interfaces and consumers as you like. Otherwise it isn't a good container.
    • When struggling starting with DI (and containers) I would advise wiring it up yourself. This gives you great insight in how it works and provides flexibility. Mark Seemann has written a lot about this stuff.
    • Your service's dependencies seem awfully crowded. Can't you refactor to less dependencies by combining some (maybe by a Facade)?
    • Making interfaces specific (not generic) makes things a lot simpler. Generics sometimes cause more harm than good.

    I've coded up a quick example which compiles (I haven't tested it). I've used a generic interface in line with your example but used some fake implementation and string types as generic params (which aren't used):

    If this is an implementation of an interface:

    public class ClassLogic : IClassLogic<string, string>
    {
        public void Do()
        {
            // do stuff
        }
    }
    

    Then you could implement a provider which only creates the implementation when needed (via a given Func) like this:

    public class ClassLogicProvider : IClassLogic<string, string>
    {
    private readonly Func<IClassLogic<string, string>> innerLogicFactory;
    
        public ClassLogicProvider(Func<IClassLogic<string, string>> innerLogicFactory)
        {
            this.innerLogicFactory = innerLogicFactory;
        }
    
        public void Do()
        {
            var classLogic = this.innerLogicFactory();
            classLogic.Do();
        }
    }
    

    And wire it up like this:

    var container = new UnityContainer();
    Func<IClassLogic<string, string>> classLogicFunc = () =>
            {
                // Create implementation on demand
                return new ClassLogic();
            };
    container.RegisterType<IClassLogic<string, string>>(
                new InjectionFactory(c => {
                    return new ClassLogicProvider(classLogicFunc);
                })
            );
    

    This should give you the desired Lazy creation when to implementation is needed.