Geeks With Blogs
John Blumenauer's Blog .NET Development and Community Nuggets
Last Saturday(04/04/09), I had the fortune to attend the Pittsburgh .NET Code Camp(http://codecamppgh.com/codecamp.aspx) and present my session on the Unity Application Block- Dependency Injection and Inversion of Control. There were several excellent questions posed to me by attendees (who seemed to be really thinking about how to use Unity and dependency injection in their apps). However, the one question that really caused me to dig a little deeper into the Unity API was whether it is possible to register types in the Unity container and then programmatically specify which constructor will be used when the object is resolved?
By design, Unity will choose the constructor with the most parameters when more than one constructor is available (unless a constructor is annotated with the [InjectionConstructor] attribute). However, after a little digging, I determined that by utilizing the Unity Fluent Interface, it is possible to resolve for a specific interface and have a specific constructor called when the object is created.
    5 using Microsoft.Practices.Unity;
    6 
    7 namespace ConstructorSelectionFluentInterface
    8 {
    9     classProgram
   10     {
   11         staticvoid Main(string[] args)
   12         {
   13             IUnityContainer container = newUnityContainer();
   14 
   15             IMapView mapView = newMapView();
   16             ILogger logger = newConsoleLogger();
   17 
   18             container.RegisterType<IMapDataSource, MapDataSource>("One").Configure<InjectedMembers>().ConfigureInjectionFor<MapDataSource>("One", newInjectionConstructor(mapView));
   19 
   20             container.RegisterType<IMapDataSource, MapDataSource>("Two").Configure<InjectedMembers>().ConfigureInjectionFor<MapDataSource>("Two", newInjectionConstructor(mapView, logger));
   21 
   22             var mapDataSource = container.Resolve<IMapDataSource>("One");
   23             mapDataSource.GetMapData();
   24 
   25             mapDataSource = container.Resolve<IMapDataSource>("Two");
   26             mapDataSource.GetMapData();
   27 
   28             mapDataSource = container.Resolve<IMapDataSource>("One");
   29             mapDataSource.GetMapData();
   30 
   31         }
   32     }
   33 }
 
Using the Unity Fluent Interface, it is possible to specify the parameters to be injected into the constructor for a given type. The key, however, is to provide specific names when executing the registration.  This will provide the necessary identification so that later when the objects are resolved, the names can be used to not only specify the object requested, but also which constructor will be used when instantiating the object.
    7 namespace ConstructorSelectionFluentInterface
    8 {
    9     publicinterfaceILogger
   10     {
   11         void Log(string value);
   12     }
   13 }
 
    6 namespace ConstructorSelectionFluentInterface
    7 {
    8     publicinterfaceIMapDataSource
    9     {
   10         void GetMapData();
   11     }
   12 }
 
    6 namespace ConstructorSelectionFluentInterface
    7 {
    8     publicinterfaceIMapView
    9     {
   10     }
   11 }
 
    7 namespace ConstructorSelectionFluentInterface
    8 {
    9     publicclassConsoleLogger:ILogger
   10     {
   11 
   12         #region ILogger Members
   13 
   14         publicvoid Log(string value)
   15         {
   16             Console.WriteLine(value);
   17         }
   18 
   19         #endregion
   20     }
   21 }
 
    6 namespace ConstructorSelectionFluentInterface
    7 {
    8     publicclassMapDataSource : IMapDataSource
    9     {
   10         privateILogger logger;
   11         privateIMapView mapView;
   12 
   13         public MapDataSource()
   14         {
   15 
   16         }
   17 
   18         public MapDataSource(IMapView mapView)
   19         {
   20             this.mapView = mapView;
   21         }
   22 
   23         public MapDataSource(IMapView mapView, ILogger logger)
   24         {
   25             this.mapView = mapView;
   26             this.logger = logger;
   27 
   28         }
   29 
   30         #region IMapDataSource Members
   31 
   32         publicvoid GetMapData()
   33         {
   34             if (this.logger != null)
   35                 this.logger.Log("Logger is not null");
   36             else
   37                 Console.WriteLine("logger is null!");
   38         }
   39 
   40         #endregion
   41     }
   42 }
 
    6 namespace ConstructorSelectionFluentInterface
    7 {
    8     publicclassMapView : IMapView
    9     {
   10     }
   11 }
 
As an aside, this technique is also useful in the event that you decide not to use Unity any longer since there are no Unity specific attributes in the class.
While I tend to favor the registration of types in a more simplistic and consistent manner, it’s nice to see that Unity provides viable options for developers who are thinking “out of the box.”
 
Hope this helps,
John Blumenauer
Posted on Tuesday, April 7, 2009 10:17 PM | Back to top


Comments on this post: Using the Unity Fluent Interface to Specify Constructors

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © John Blumenauer | Powered by: GeeksWithBlogs.net