Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

named type not used for constructor injection

I have a simple console application where I have the following setup:

public interface ILogger
{
   void Log(string message);
}

class NullLogger : ILogger
{
   private readonly string version;

   public NullLogger()
   {
      version = "1.0";
   }
   public NullLogger(string v)
   {
      version = v;
   }
   public void Log(string message)
   {
     Console.WriteLine("NULL> " + version + " : " + message);
   }
}

The configuration details are below:

<type type="UnityConsole.ILogger, UnityConsole" mapTo="UnityConsole.NullLogger, UnityConsole">
 <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
   <constructor>
     <param name="message" parameterType="System.String" >
        <value value="2.0" type="System.String"/>
     </param>
   </constructor>
 </typeConfig>

My calling code looks as below:

IUnityContainer container = new UnityContainer();
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);
ILogger nullLogger = container.Resolve<ILogger>();
nullLogger.Log("hello");

This works fine, but once I give a name to this type something like:

<type type="UnityConsole.ILogger, UnityConsole" mapTo="UnityConsole.NullLogger, UnityConsole" name="NullLogger">
 <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
   <constructor>
     <param name="message" parameterType="System.String" >
       <value value="2.0" type="System.String"/>
     </param>
   </constructor>
 </typeConfig>

The above calling code does not work even if I explicitly register the type using

container.RegisterType<ILogger, NullLogger>();

I get the error:

{"Resolution of the dependency failed, type = \"UnityConsole.ILogger\", name = \"\". Exception message is: The current build operation (build key Build Key[UnityConsole.NullLogger, null]) failed: The parameter v could not be resolved when attempting to call constructor UnityConsole.NullLogger(System.String v). (Strategy type BuildPlanStrategy, index 3)"}

Why doesn't unity look into named instances? To get it to work, I'll have to do:

ILogger nullLogger = container.Resolve<ILogger>("NullLogger");

Where is this behavior documented?

Arun

like image 685
Arun Avatar asked May 05 '10 07:05

Arun


1 Answers

As you know - there are two types of instances: named(can be many of them) and default(only one can be, and it does not have names)

Resolve( ) - does not look into named instances - it looks for default only, and if there is no default instance

  • it returns instance of T if it can be constructed or
  • exception if it can't
    • in case of interfaces
    • or when class does not have constructor,
    • or unity can't resolve parameter for constructor of this type

So let's look at your example. First question, simple one - Why did code stoped work when you pointed name in configuration. Answer is becous now there is no default instance registered for ILogger and Resolve( ) - does not look into named instances - it looks for default only.

Second question Why does it not work after container.RegisterType<ILogger, NullLogger>(); Answer is becouse unity is greedy when it choose constructors for the type. Generaly speaking it always takes the constructor where the number of parameters is bigger. So it took this one public NullLogger(string v) could not created string(you can see it in inner exception). There is no information about wich constructor to choose for default resolution. All information is about named. And that is why

ILogger nullLogger = container.Resolve<ILogger>("NullLogger");

works.

This behavior documented in help wich can be downloaded fon here http://unity.codeplex.com/releases/view/18855. Or you can take a look here http://msdn.microsoft.com/en-us/library/ff649334.aspx

like image 173
er-v Avatar answered Oct 02 '22 08:10

er-v