30

I have a code which look something like this. When trying to do a ResolveAll I expected every type registered with the IParserType to yielded from the container instance. But I didn't get any instance from Unity. Am I assuming or doing something wrong here.

public class ResolveAllDemo
{
    public ResolveAllDemo()
    {
        var container = new UnityContainer();

        container.RegisterInstance<IUnityContainer>(container);
        container.RegisterType<IParser, SuperParser>();
        container.RegisterType<IParser, DefaultParser>();
        container.RegisterType<IParser, BasicParser>();
        //   container.RegisterType<Crawler>();
        container.RegisterType<IParserFactory, UnityParserFactory>();

        foreach (var registeredMember in container.ResolveAll<IParser>())
        {
            LoggingUtility.LogerInstance.Logger.Write(registeredMember);
        }
    }

    #region Resolve Demo

    public interface IParserFactory
    {
        IEnumerable<IParser> BuildParsers();
    }

    public class UnityParserFactory : IParserFactory
    {
        private IUnityContainer _container;

        public UnityParserFactory(IUnityContainer container)
        {
            _container = container;
        }

        public IEnumerable<IParser> BuildParsers()
        {
            return _container.ResolveAll<IParser>();
        }
    }

    public class DefaultParser : IParser
    {
        public override string ToString()
        {
            return "DefaultParser";
        }
    }

    public class BasicParser : IParser
    {
        public override string ToString()
        {
            return "BasicParser";
        }
    }

    public class SuperParser : IParser
    {
        public override string ToString()
        {
            return "SuperParser";
        }
    }

    public interface IParser
    {
    }

    #endregion Resolve Demo
}
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
Arshad Badar Khan
  • 942
  • 1
  • 12
  • 32

2 Answers2

57

You are not registering 3 different implementations of IParser. You create one default mapping IParser -> SuperParser and then overwrite it with IParser -> DefaultParser and then you overwrite it again with IParser -> BasicParser.

If you want to register all three of them you have to provide named registrations like

container.RegisterType<IParser, SuperParser>("Super");
container.RegisterType<IParser, DefaultParser>("Default");
container.RegisterType<IParser, BasicParser>("Basic");

In addition ResolveAll does not include the default mapping (the one without a name). It only resolves those mappings of IParser that were registered as named mappings.

Sebastian Weber
  • 6,766
  • 2
  • 30
  • 49
  • 1
    Do you know if the fact that the default is not returned is by design or is it a bug? – Nicolas De Irisarri Mar 12 '15 at 14:00
  • @NicolasIrisarri Apart from the fact that it's in the codebase since at least v1.2 I believe it's by design. You can easily work around it if you register the default mapping again with a name (e.g. "default"). – Sebastian Weber Mar 12 '15 at 15:43
  • 4
    this really is valuable information. unity behaving this way does not make any sense – vip32 Dec 13 '16 at 16:15
  • 1
    I think Unity really should throw an exception instead of just owerwriting or even better make default behavior being Unity registering the registered type as name. – Jonas Stensved Mar 10 '17 at 17:33
  • @JonasStensved Other containers remember multiple registrations as default and use that to create chains of objects at resolve-time. Unity overwrites that registration. Different containers, different behaviors. But you can always expand Unity to match your preferences. – Sebastian Weber Mar 13 '17 at 09:24
  • Unity really is a terrible POS –  May 24 '18 at 09:24
17

You need to register your parsers with a name, if you want to resolve all Parsers from the container.

Here´s the update code from your constructor:

public ResolveAllDemo() 
{

  var container = new UnityContainer();

  container.RegisterType<IParser, SuperParser>("SuperParser");
  container.RegisterType<IParser, DefaultParser>("DefaultParser");
  container.RegisterType<IParser, BasicParser>("BasicParser");

  container.RegisterType<IParserFactory, UnityParserFactory>();

  foreach (var registeredMember in container.ResolveAll<IParser>())
  {
     LoggingUtility.LogerInstance.Logger.Write(registeredMember);
  }
}

Note:

There is no need for the following code, cause the container registers itself during construction of the container.

container.RegisterInstance<IUnityContainer>(container);
// not needed cause UnityContainer registers itself on construction
Jehof
  • 34,674
  • 10
  • 123
  • 155