tags:

views:

244

answers:

1

Hi,

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

+1  A: 

As you know - there is 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 greed when it choose onstructors 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

er-v
Very nice explanation. Thanks Alex.
Arun