Search code examples
c#inversion-of-controlunity-containerioc-container

Unity: Resolve list of all registered instances of type in specific order


I'm registering multiple instances of a specific class implementing some interface (in the example IInteractivityTarget).

RootContainer.RegisterInstance<IInteractivityTarget>(Name, new InteractivityTarget(Name));

I also registered the Enumerable of the type, to automaticaly resolve a list of all registered instances.

Container.RegisterType<IEnumerable<IInteractivityTarget>, IInteractivityTarget[]>();

Now the problem is that I have no chance to define some ordering(-info) to get the items in a specific order when resolvin them. How can this be achieved? I dont want to extend the IInteractivityItem with a SortHint-property.


More detailed example:

public void RegisterInteractivity(string name, string sortHint){
    if (!Container.IsRegistered(typeof(IEnumerable<IInteractivityTarget>))){
            Container.RegisterType<IEnumerable<IInteractivityTarget>, IInteractivityTarget[]>();
    }

    Container.RegisterInstance<IInteractivityTarget>(Name, new InteractivityTarget(Name, sortHint));
}

RegisterInteravtivity("Show in View A", "aaa");
RegisterInteravtivity("Show in View A", "bbb");
RegisterInteravtivity("Show in View A", "ddd");
RegisterInteravtivity("Show in View A", "eee");
RegisterInteravtivity("Show in View A", "ccc");
RegisterInteravtivity("Show in View A", "aab");


/// --> this should be resolved ordered by SortHint
var interactivityTargets = Container.Resolve<IEnumerable<IInteractivity>>()

Solution

  • I dont want to extend the IInteractivityItem with a SortHint-property

    You will need some kind of sort-hint, either as property or attribute.

    Alternatively, you can create a custom registry that preserves the order.

    Example:

    public interface IInteractivityRegistry
    {
        void Add<T>() where T : IInteractivity;
        IReadOnlyList<IInteractivity> ResolveAllInOrder();
    }
    
    internal class UnityInteractivityRegistry : IInteractivityRegistry
    {
        public UnityInteractivityRegistry(IUnityContainer container)
        {
            _container = container;
        }
    
        #region IInteractivityRegistry
        public void Add<T>() where T : IInteractivity
        {
            _interactivities.Add( typeof(T) );
        }
    
        public IReadOnlyList<IInteractivity> ResolveAllInOrder()
        {
            return _interactivities.Select( x => _container.Resolve( x ) ).ToArray();
        }
        #endregion
    
        #region private
        private readonly List<Type> _interactivities = new List<Type>();
        private readonly IUnityContainer _container;
        #endregion
    }
    

    Note that we inject the container even though that's obviously a code smell. But the UnityInteractivityRegistry is more or less an extension to the container, so I guess, it's justified. Also, in a real world application, IInteractivityRegistry would have to be split into two interfaces, of course.