Extending and Demonstrating the Type Tracking Extension for Unity
·1166 words·6 mins·
Programming
IoC
ALT.NET
Unity
Author
David Buksbaum
Table of ContentsTable of Contents
Recently, I have received a few requests for some changes and an example for my Type Tracking Extension for Unity. This post is to address those requests. Of course, all of the source code for this post is added to the
GitHub
project
Unity Extensions
.
Part One – Extension Methods for the Type Tracking Extension#
The number one request I have received, and my own number one issue with using the Type Tracking Extension, is the verbosity of each method call. Here is a typical method call.
This is the typical extension usage model for Unity. Besides the verbosity, it implies that I am configuring the extension, when I am just trying to use it. I try to avoid code that implies something other than what I intend, so this syntax bothers me.
To address this issue, I have added a new class of extension methods to the Type Tracking project. Here is the source code.
namespacehazware.unity.extensions{/// <summary>/// Extension methods to simplify using the TypeTrackingExtension for Unity./// Requires .NET 3.5/// </summary>publicstaticclassUnityExtensions{#regionCanResolve/// <summary>/// Determines whether this type can be resolved as the default./// </summary>/// <typeparam name="T">The type to test for resolution</typeparam>/// <param name="container">The unity container.</param>/// <returns>/// <c>true</c> if this instance can resolve; otherwise, <c>false</c>./// </returns>publicstaticboolCanResolve<T>(thisIUnityContainercontainer){returncontainer.Configure<TypeTrackingExtension>().CanResolve<T>();}/// <summary>/// Determines whether this type can be resolved with the specified name./// </summary>/// <typeparam name="T">The type to test for resolution</typeparam>/// <param name="container">The unity container.</param>/// <param name="name">The name associated with the type.</param>/// <returns>/// <c>true</c> if this instance can resolve; otherwise, <c>false</c>./// </returns>publicstaticboolCanResolve<T>(thisIUnityContainercontainer,stringname){returncontainer.Configure<TypeTrackingExtension>().CanResolve<T>(name);}/// <summary>/// Determines whether this instance can be resolved at all with or without a name./// </summary>/// <typeparam name="T">The type to test for resolution</typeparam>/// <param name="container">The unity container.</param>/// <returns>/// <c>true</c> if this instance can resolve; otherwise, <c>false</c>./// </returns>publicstaticboolCanResolveAny<T>(thisIUnityContainercontainer){returncontainer.Configure<TypeTrackingExtension>().CanResolveAny<T>();}#endregion#regionTryResolve/// <summary>/// Tries to resolve the type, returning null if not found./// </summary>/// <typeparam name="T">The type to try and resolve</typeparam>/// <param name="container">The unity container.</param>/// <param name="container">The unity container.</param>/// <returns>An object of type <see cref="T"/> if found, or <c>null</c> if not.</returns>/// <param name="container">The unity container.</param>publicstaticTTryResolve<T>(thisIUnityContainercontainer){returncontainer.Configure<TypeTrackingExtension>().TryResolve<T>();}/// <summary>/// Tries to resolve the type with the specified of name, returning null if not found./// </summary>/// <typeparam name="T">The type to try and resolve</typeparam>/// <param name="container">The unity container.</param>/// <param name="name">The name associated with the type.</param>/// <returns>An object of type <see cref="T"/> if found, or <c>null</c> if not.</returns>publicstaticTTryResolve<T>(thisIUnityContainercontainer,stringname){returncontainer.Configure<TypeTrackingExtension>().TryResolve<T>(name);}/// <summary>/// Tries to resolve the type, returning the passed in defaultValue if not found./// </summary>/// <typeparam name="T">The type to try and resolve</typeparam>/// <param name="container">The unity container.</param>/// <param name="defaultValue">The default value.</param>/// <returns>An object of type <see cref="T"/> if found, or the <see cref="defaultValue"/> if not.</returns>publicstaticTTryResolve<T>(thisIUnityContainercontainer,TdefaultValue){returncontainer.Configure<TypeTrackingExtension>().TryResolve<T>(defaultValue);}/// <summary>/// Tries to resolve the type, returning the passed in defaultValue if not found./// </summary>/// <typeparam name="T">The type to try and resolve</typeparam>/// <param name="container">The unity container.</param>/// <param name="name">The name associated with the type.</param>/// <param name="defaultValue">The default value.</param>/// <returns>An object of type <see cref="T"/> if found, or the <see cref="defaultValue"/> if not.</returns>publicstaticTTryResolve<T>(thisIUnityContainercontainer,stringname,TdefaultValue){returncontainer.Configure<TypeTrackingExtension>().TryResolve<T>(name,defaultValue);}#endregion#regionResolveAll/// <summary>/// Resolves all elements of a type, including the default./// </summary>/// <typeparam name="T">The type to resolve</typeparam>/// <param name="container">The unity container.</param>/// <returns><see cref="IEnumerable"/> of T</returns>publicstaticIEnumerable<T>ResolveAllToEnumerable<T>(thisIUnityContainercontainer){returncontainer.Configure<TypeTrackingExtension>().ResolveAll<T>();}/// <summary>/// Resolves all registered T in the container, conditionally including the default unnamed/// registered T. When includeDefault is false, this is the same as the normal Unity/// ResolveAll./// </summary>/// <typeparam name="T">The type to resolve</typeparam>/// <param name="container">The unity container.</param>/// <param name="includeDefault">if set to <c>true</c> include default value, else do not include default.</param>/// <returns><see cref="IEnumerable"/> of T</returns>publicstaticIEnumerable<T>ResolveAllToEnumerable<T>(thisIUnityContainercontainer,boolincludeDefault){returncontainer.Configure<TypeTrackingExtension>().ResolveAll<T>(includeDefault);}/// <summary>/// Resolves all elements of a type, including the default, and returns /// as an array of T./// </summary>/// <typeparam name="T">The type to resolve</typeparam>/// <param name="container">The unity container.</param>/// <returns>Array of T</returns>publicstaticT[]ResolveAllToArray<T>(thisIUnityContainercontainer){returncontainer.Configure<TypeTrackingExtension>().ResolveAllToArray<T>();}/// <summary>/// Resolves all registered T in the container, conditionally including the default unnamed/// registered T. When includeDefault is false, this is the same as the normal Unity/// ResolveAll./// </summary>/// <typeparam name="T">The type to resolve</typeparam>/// <param name="container">The unity container.</param>/// <param name="includeDefault">if set to <c>true</c> include default value, else do not include default.</param>/// <returns>Array of T</returns>publicstaticT[]ResolveAllToArray<T>(thisIUnityContainercontainer,boolincludeDefault){returncontainer.Configure<TypeTrackingExtension>().ResolveAllToArray<T>(includeDefault);}#endregion}}
Using these extension methods makes the above sample code look like this:
container.TryResolve<ITest>();
This is more concise, and more importantly, clearly states the meaning of the code. However, the catch for this syntactic sugar is that it uses extension methods. That means that .NET 3.5 is now a requirement for the Type Tracking Extension.
Part Two – Type Tracking Usage SampleTypeTrackingExtensionsReferences#
I have received a few requests for a simple example of how to use the Type Tracking Extension. So here it is.
Step 1 – Add a reference to the hazware.unity.extensions assembly into your project.
Step 2 – Add the following using statement to your source file:
usinghazware.unity.extensions;
Step 3 – Register the extension with the Unity container. Here is some sample code: