Search code examples
c#dependency-injectionunity-container

Which lifetime manager to use to create new instances in foreach loops using Unity


I got an example where I want to use DI to create instances of a class in a foreach loop but cannot figure which lifetime manager to use. The default lifetime manager will obviously only use the instance injected in the controller where I want to create new instances each time the instance is called as illustrated in the example below. I'm using Microsoft Unity

Simple interface class

public interface ISomeClass 
{
    string GetValue(string value);
}

public class SomeClass : ISomeClass
{
    public string GetValue(string value) 
    {
        return value;
    }
}

Register in container

container.RegisterType<ISomeClass, SomeClass>(new TransientLifetimeManager());

Implementation

private readonly SomeClass _someClass;

public MyController(SomeClass someClass)
{
    _someClass = someClass;
}

// someStringList would contain values like "hello", "world", "o", "hai"
public void Whatever(List<string> someStringList) 
{
    List<string> otherStringList = new List<string>();

    foreach (var someString in someStringList)
    {
        // _someClass.GetValue will simply return the same value
        otherStringList.Add(_someClass.GetValue(someString));
    }

    // otherStringList contain as many elements as the someStringList 
    // but all will be the same as the last element in the list
}

Solution

  • The TransientLifetimeManager lifetime manager is the way to go. That one will create new object each time you, or container itself, call Resolve.


    So the point is to initiate that Resolve somehow within the foreach. The naive\simple approach could be to inject IUnityContainer itself into your controller, the IUnitContainer itself is always available...

    private readonly IUnityContainer _container;
    
    public MyController(IUnityContainer container)
    {
        _container = container;
    }
    

    then resolve ISomeClass manually:

    foreach (var someString in someStringList)
    {
         var someClass = _container.Resolve<ISomeClass>();
         otherStringList.Add(_someClass.GetValue(someString));
    }
    

    Generally, I would prefer more some kind of factory or prototype pattern instead of injecting the IUnityContainer itself as that might be considered as a bad practice. The container should be used more as an invisible helper instead of first class citizen...

    The easy factory approach can be to register the simple factory method:

    _container.RegisterType<Func<ISomeClass>>(new InjectionFactory(_ => 
                new Func<ISomeClass> (() => _container.Resolve<ISomeClass>())));
    

    then you can inject this into your controller:

    private readonly Func<ISomeClass> _factory;
    
    public MyController(Func<ISomeClass> factory)
    {
        _factory = factory;
    }
    

    and then you it as:

    foreach (var someString in someStringList)
    {
         ISomeClass someClass = _factory();
         otherStringList.Add(_someClass.GetValue(someString));
    }
    

    The good thing about the second approach is that you have explicit dependency instead of injecting IoC, which makes your design cleaner.