Allowing the Simple Service Locator to resolve arrays and other list types

The default behavior of the Simple Service Locator is to resolve collections of types through the IEnumerable<T> interface. Resolving a set of elements using other collection types is possible by registrering a mapping on a per type basis, such as can be seen the following example:

container.RegisterAll<IWeapon>(new Katana(), new Tanto(), new Gun());
container.Register<IWeapon[]>(() => container.GetAllInstances<IWeapon>().ToArray());

When having many collections of types that need to be resolved in this way, the registration can be come cumbersome. Alternatively you can revert to unregistered type resolution, as can be seen in the following example:

public static class SslCollectionRegistrationExtensions
{
    private interface IResolve
    {
        SimpleServiceLocator Container { get; set; }
        object GetInstance();
    }

    public static void AllowToResolveArrays(this SimpleServiceLocator container)
    {
        container.ResolveUnregisteredType += (s, e) =>
        {
            if (e.UnregisteredServiceType.IsArray)
            {
                // Allow an IEnumerable<T> to be resolved as T[].
                Type elementType = e.UnregisteredServiceType.GetElementType();
                RegisterArrayResolver(e, container, elementType);
            }
            else if (e.UnregisteredServiceType.IsGenericType &&
                e.UnregisteredServiceType.GetGenericTypeDefinition() == typeof(IList<>))
            {
                // Allow an IEnumerable<T> to be resolved as IList<T>.
                Type elementType = e.UnregisteredServiceType.GetGenericArguments()[0];
                RegisterArrayResolver(e, container, elementType);
            }
        };
    }

    private static void RegisterArrayResolver(UnregisteredTypeEventArgs e, 
        SimpleServiceLocator container, Type elementType)
    {
        IResolve resolver = CreateArrayResolver(elementType);
        resolver.Container = container;
        e.Register(() => resolver.GetInstance());
    }

    private static IResolve CreateArrayResolver(Type elementType)
    {
        return Activator.CreateInstance(typeof(ArrayResolver<>)
            .MakeGenericType(elementType)) as IResolve;
    }

    private sealed class ArrayResolver<T> : IResolve
    {
        public SimpleServiceLocator Container { get; set; }

        public object GetInstance()
        {
            return this.Container.GetAllInstances<T>().ToArray();
        }
    }
}
After copying the previous code snippet to your project, you can allow mapping of array types to IEnumerable<T> for all registered collections, with the following line:

container.AllowToResolveArrays();

Last edited Jan 26, 2011 at 12:11 PM by dot_NET_Junkie, version 2