RegisterAll inconsistency

Jun 18, 2012 at 2:43 PM

I'm using the RegisterAll extension method in SimpleInjector.Extensions.NonGenericRegistrationsExtensions

public static void RegisterAll(this Container container, Type serviceType, IEnumerable<Type> serviceTypes);

It's giving me different results than other uses of RegisterAll. 
I get a collection using GetAllInstances.  When I iterate through the objects they are re-created on each iteration.

I'd love some help.
Here is some demonstration code:

class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Debug.WriteLine("Iteration works as expected.");
            Container container1 = new Container();
            container1.RegisterAll<ITest>(new TestA(), new TestB());

            IEnumerable<ITest> tests1 = container1.GetAllInstances<ITest>();

            System.Diagnostics.Debug.WriteLine("First Iteration:");
            foreach (ITest test in tests1)
            {
                System.Diagnostics.Debug.WriteLine(test.Name + " - " + test.GetHashCode());
            }

            System.Diagnostics.Debug.WriteLine("Second Iteration:");
            foreach (ITest test in tests1)
            {
                System.Diagnostics.Debug.WriteLine(test.Name + " - " + test.GetHashCode());
            }

            System.Diagnostics.Debug.WriteLine("Iteration DOES NOT work as expected.");
            System.Diagnostics.Debug.WriteLine("New instances created when interating.");
            Container container2 = new Container();
            container2.RegisterAll(typeof(ITest), new Type[] { typeof(TestA), typeof(TestB) });

            IEnumerable<ITest> tests2 = container2.GetAllInstances<ITest>();

            System.Diagnostics.Debug.WriteLine("First Iteration:");
            foreach (ITest test in tests2)
            {
                System.Diagnostics.Debug.WriteLine(test.Name + " - " + test.GetHashCode());
            }

            System.Diagnostics.Debug.WriteLine("Second Iteration:");
            foreach (ITest test in tests2)
            {
                System.Diagnostics.Debug.WriteLine(test.Name + " - " + test.GetHashCode());
            }
        }
    }
Coordinator
Jun 18, 2012 at 3:08 PM
Edited Dec 15, 2012 at 9:12 AM

When registering a list of Type objects using RegisterAll, during iterating the collection returned from GetAllInstances, will call back into the container. This will be functionally equivalent to doing the following:

private IEnumerable<T> MakeIterator<T>(Container container, Type[] types)
{
    foreach (var type in types)
    {
        yield return (T)container.GetInstance(type);
    }
}

IEnumerable<IService> services = MakeIterator<IService>(container,
    new Type[] { typeof(Service1), typeof(Service2) });

container.RegisterAll<IService>(services);

Since the container is called to create that type, the container will get that type by its registered lifestyle. This allows you to explicitly specify what lifestyle each registered type should have, and this allows you to give each item a different lifestyle. For instance:

container.Register<Service1>();
container.RegisterSingle<Service2>(); container.RegisterAll<IService>(new Type[] { typeof(Service1), typeof(Service2) });

This registers a collection that yields a new instance of the Service1 each time it is iterated, but always yields the same instance of Service2.

Not only does this allow you to differ the lifestyle per registered type, it also allows you to refer to abstract types.

In fact this behavior is not different from the other overloads, since you can use the other overloads to get this behavior (as you've seen in the first example), but since you probably registered a fixed list of initiated instances (singletons), you see this different behavior.

In other words, if you want the list of registered services to be resolved as singleton, you will have to register each individually as singleton.

I hope this helps.

Marked as answer by dot_NET_Junkie on 11/4/2013 at 1:52 AM