Type Tracking Extension for Unity
Edit: Source code posted to Hazware Unity Extensions on GitHub
My personal inversion of control container is Unity. However, I occasionally find myself looking for functionality from the other .NET IoC containers I have used, such as Ninject and Castle Windsor. Here is the code that came out from trying to solve this need.
I was working on some Unit of Work code for NHibernate and I found the need to query the container to check if a type was registered. I checked the Unity documentation for the IUnityContainer.Resolve<>() method, and as usual, the documentation always seems to be missing the piece of information I need. It did not describe the result of calling the container for a type that is not registered. Having used Unity for a while now, I was pretty sure it through an exception, but just be sure, I wrote a quick test.
[Test] public void TestUnity() { IoC.Container.Resolve<IDisposable>(); }
And result:
Microsoft.Practices.Unity.ResolutionFailedException: Resolution of the dependency failed, type = "System.IDisposable", name = "". Exception message is: The current build operation (build key Build Key[System.IDisposable, null]) failed: The current type, System.IDisposable, is an interface and cannot be constructed. Are you missing a type mapping?
I could not find another way to check for type registration, so off to Google I went. One discussion from the Unity discussion group seemed to cover this program [see: IsInstanceRegistered?]. This seemed to be the answer, until I compared against my unit tests to validate my usage. The solution provided does not provide for checked for default or named registered types. The problem is that Unity has a keyed resolver in that it either returns a default registration that is unnamed, or a specifically named registration. Thus, it is possible for this check to return true, but for the Resolve call to fail. I wanted something more in line with Unity’s usage model.
I did find one other posted solution. That solution recommend just doing a ResolveAll and returning true if the collection was not empty. However, this is highly inefficient. It forces resolution of the types, triggering instantiation, even if not needed.
Given these limitations, I decided to write my own solution. I like the idea of doing it as a Unity extension, so I retained that model. So here is my code for solution.
public class TypeTrackingExtension : UnityContainerExtension { #region Fields private readonly Dictionary<Type, HashSet<string>> _registeredTypes = new Dictionary<Type, HashSet<string>>(); #endregion #region Private Methods protected override void Initialize() { Context.RegisteringInstance += OnNewInstance; Context.Registering += OnNewType; } private void OnNewInstance(object sender, RegisterInstanceEventArgs e) { HashSet<string> names; string name = string.IsNullOrEmpty(e.Name) ? string.Empty : e.Name; if (!_registeredTypes.TryGetValue(e.RegisteredType, out names)) { // not found, so add it _registeredTypes.Add(e.RegisteredType, new HashSet<string> { name }); } else { // already added type, so add name names.Add(name); } } private void OnNewType(object sender, RegisterEventArgs e) { HashSet<string> names; string name = string.IsNullOrEmpty(e.Name) ? string.Empty : e.Name; if (!_registeredTypes.TryGetValue(e.TypeFrom, out names)) { // not found, so add it _registeredTypes.Add(e.TypeFrom, new HashSet<string> { name }); } else { // already added type, so add name names.Add(name); } } #endregion #region CanResolve /// <summary> /// Determines whether this type can be resolved as the default. /// </summary> /// <typeparam name="T"></typeparam> /// <returns> /// <c>true</c> if this instance can resolve; otherwise, <c>false</c>. /// </returns> public bool CanResolve<T>() { return CanResolve<T>(null); } /// <summary> /// Determines whether this type can be resolved with the specified name. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name">The name.</param> /// <returns> /// <c>true</c> if this instance can be resolved with the specified name; otherwise, <c>false</c>. /// </returns> public bool CanResolve<T>(string name) { HashSet<string> names; if (_registeredTypes.TryGetValue(typeof(T), out names)) { return names.Contains(name ?? string.Empty); } return false; } /// <summary> /// Determines whether this instance can be resolved at all. /// </summary> /// <typeparam name="T"></typeparam> /// <returns> /// <c>true</c> if this instance can be resolved at all; otherwise, <c>false</c>. /// </returns> public bool CanResolveAny<T>() { return _registeredTypes.ContainsKey(typeof(T)); } #endregion #region TryResolve /// <summary> /// Tries to resolve the type, returning null if not found. /// </summary> /// <typeparam name="T">The type to try and resolve.</typeparam> /// <returns>An object of type <see cref="T"/> if found, or <c>null</c> if not.</returns> public T TryResolve<T>() { return TryResolve<T>(default(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="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> public T TryResolve<T>(string name) { return TryResolve<T>(name, default(T)); } /// <summary> /// Tries to resolve the type, returning null if not found. /// </summary> /// <typeparam name="T">The type to try and resolve.</typeparam> /// <param name="defaultValue">The default value to return if type not found.</param> /// <returns>An object of type <see cref="T"/> if found, or the <see cref="defaultValue"/> if not.</returns> public T TryResolve<T>(T defaultValue) { if (!CanResolve<T>()) return defaultValue; return Container.Resolve<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="name">The name associated with the type.</param> /// <param name="defaultValue">The default value to return if type not found.</param> /// <returns>An object of type <see cref="T"/> if found, or the <see cref="defaultValue"/> if not.</returns> public T TryResolve<T>(string name, T defaultValue) { if (!CanResolve<T>(name)) return defaultValue; return Container.Resolve<T>(name); } #endregion }
Source Code TypeTrackingExtension.cs


Hi,
how I use TypeTrackingExtension ? sample code,please !!!
thanks
Hi espinete. I will post up an example a little later today.
Hi espinete. See the new post Extending and Demonstrating the Type Tracking Extension for Unity. I hope this helps.