Eric's Blog

Day to day experience in .NET
Welcome to Blogs @ IRM Sign in | Join | Help
 Search

Disclaimer

The content of this site is my own personal opinion and does not in any way represent my employer, it's subsideries or affiliates. These postings are provided "AS IS" with no warranties, and confer no rights.

This Blog

Dependency Injection: The Locator And LifetimeContainer

The Locator is a dictionary of weak object references (so it does not keep objects alive). By adding objects to the locator, you make it possible for other code to ask the locator for the object, and get a reference to it. The object is added with a corresponding key. The key can be anything, but it will often be an object of type DependencyResolutionLocatorKey. The reason to this is that the DependencyAttribute (which I have not covered yet) uses a DependencyResolutionLocatorKey to locate objects. It really doesn't matter though, as long as the code that wants to get hold of an object uses the same key to search for it. Now let's look at some examples of adding objects to the locator.
 
locator.Add(new DependencyResolutionLocatorKey(typeof(ICustomerView), null), customerView);
locator.Add(new DependencyResolutionLocatorKey(typeof(Window), null
), window);
locator.Add(new DependencyResolutionLocatorKey(null
, idToBuild), window);
locator.Add(new DependencyResolutionLocatorKey(typeof(Window
), idToBuild), window);
 
One really interesting thing with the examples above is in the first line where I add an object with an interface as part of the key. This allows you to use some really loose coupling in your code, and of course you could also use a base class as well.
The DependencyResolutionLocatorKey can be both an object type and a string identifier, or just one of them as the three last lines shows. It also possible to add the same object more than once under different keys. Code that wants to get hold of objects from the locator dictionary just uses methods like Contains and Get.
Important to note in the text above is that the locator does not keep the objects alive, and because of that you will have to keep a reference to it or use a LifetimeContainer. You can register an object with a LifetimeContainer, and it will keep that object alive until you dispose the LifetimeContainer. The LifetimeContainer itself should also be added to the locator. The SingletonStrategy depends on that a LifetimeContainer is available in the locator dictionary. A typical setup of the locator is therefore something like this:
 
private static Locator locator = new Locator();
private static LifetimeContainer lifetime = new LifetimeContainer
();

static
MyBuilder()
{
    locator.Add(typeof(ILifetimeContainer
), lifetime);
}
 
Of course it doesn't matter if you use static variables or not, that will depend on your case, but in this example I choose that and I use the static constructor to add the LifetimeContainer to the locator dictionary. Note that the lifetime container is not added with a DependencyResolutionLocatorKey, but rather just the type of the interface ILifetimeContainer. To show you an example of how to use the lifetime container, I just copied an internal method of the CreationStrategy.
 
private void RegisterObject(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
    if (context.Locator != null
)
    {
        ILifetimeContainer lifetime = context.Locator.Get<ILifetimeContainer>(typeof(ILifetimeContainer), SearchMode
.Local);

        if (lifetime != null
)
        {
            ISingletonPolicy singletonPolicy = context.Policies.Get<ISingletonPolicy
>(typeToBuild, idToBuild);

            if (singletonPolicy != null
&& singletonPolicy.IsSingleton)
            {
                context.Locator.Add(new DependencyResolutionLocatorKey
(typeToBuild, idToBuild), existing);
                lifetime.Add(existing);

                if
(TraceEnabled(context))
                    TraceBuildUp(context, typeToBuild, idToBuild, Properties.Resources
.SingletonRegistered);
            }
        }
    }
}
 
The code that is most interesting here is towards the end when the created object (the existing variable) is added first to the locator and on the next line to the lifetime container. If you study the code a little bit closer you can se how the SingletonPolicy is used to determine if the object should be a singleton object or not (I wrote about policies in my last post) and in the beginning of the method you could also see an example of using the locator to get hold of the lifetime container. Worth noting in this line is the last parameter, options, which in this case has the value SearchMode.Local. The other value for the SearchMode enumeration is Up. The reason is that you can have locators in hierarchies. An overload of the constructor of the Locator object takes another locator object. This is an important concept, since you can only add a single object on one key (of course), in a specific locator.
For example if you have an Application object as your root object for the application and a window object representing each window in a MDI application (like for example Microsoft Word, Excel and other Office applications).
 
Application
  Windows
    Window
 
If you want to add the Window object to the locator to make it available for the actual Form/View that it represents this will only be possible for the first window if you only have one locator dictionary. This of course will also result in that when the second Form/View asks for the Window object it will get the first Form/View Window object. The solution to this problem is to have a root locator for the application object and then create a new one for each Window object that is created, with the Application objects locator as parent.
 
public sealed class Window
{
    private void
CreateBuilder()
    {
        this.builder = this
.Application.Builder;
        this.locator = new Locator(this.Application.Locator
);

        
this.locator.Add(new DependencyResolutionLocatorKey(typeof(Window), null), this);
    }
}
 
CAB uses this concept so that each WorkItem gets it own Locator with the parent WorkItem's Locator as parent. This way it is possible for all code to ask for the WorkItem which always will get the correct WorkItem.
Published den 29 augusti 2006 14:30 by ericqu

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Submit
Powered by Community Server, by Telligent Systems