IsRegistered on Unity Container for Generic Type
This post just describes a bug that is there in the Unity (3.5.1404) IoC container, when using the IsRegistered extension method, to check for generic types and a possible fix for it.
Table of Contents
This post just describes a bug that is there in the Unity (3.5.1404) IoC container, when using the IsRegistered extension method, to check for generic types and a possible fix for it.
Unity IoC container provides [IsRegistered](http://msdn.microsoft.com/en-us/library/microsoft.practices.unity.unitycontainerextensions.isregistered(v=pandp.51).aspx) extension method, that can be used to check whether a registration exists for a given type and name (can be null too) combination. When a generic type is registered in the container and trying to check IsRegistered using a concrete typed version of the generic interface it returns false.
As shown in the below code snippet, calling IsRegistered on a non-generic interface(IFooBar) returns true, indicating that a registration exists. But for the generic interface(IFooGeneric<>
), trying to check if a registration exists for a concrete type (IFooGeneric<string>
- as only concrete types can be resolved from the container and an open generic type cannot be resolved) it returns false.
IUnityContainer unityContainer = new UnityContainer();
unityContainer.RegisterType(typeof(IFooBar), typeof(FooBarImplementation));
unityContainer.RegisterType(typeof(IFooGeneric<>), typeof(FooGenericImplementation<>));
var hasFooBarRegistration = unityContainer.IsRegistered<IFooBar>(); // Returns true
var hasFooGenericStringRegistration = unityContainer.IsRegistered<IFooGeneric<string>>(); // Returns False
var fooGenericString = unityContainer.Resolve<IFooGeneric<string>>(); // Resolution Succeeds
The IsRegistered method as shown below, loops through the list of available registrations looking for a match on the registered type and name. The 'typeToCheck' is the type of the object that we are trying to resolve in IsRegistered - typeof(IFooGeneric<string>)
, but the registered type is typeof(IFooGeneric<>)
. Because of this the comparison fails and the registration does not pass the where clause of the query, causing the function to return false.
var registration = from r in container.Registrations
where r.RegisteredType == typeToCheck && r.Name == nameToCheck
select r;
return registration.FirstOrDefault() != null;
To fix this, we would need to modify the where condition so that in cases where the RegisteredType is a generic type definition, it would compare with the generic type definition of 'typeToCheck', as shown below.
var genericTypeToCheck = typeToCheck.GetTypeInfo().IsGenericType
? typeToCheck.GetGenericTypeDefinition()
: null;
var registration = from r in container.Registrations
where (r.RegisteredType.GetTypeInfo().IsGenericTypeDefinition
? r.RegisteredType == genericTypeToCheck
: r.RegisteredType == typeToCheck)
&& r.Name == nameToCheck
select r;
return registration.FirstOrDefault() != null;
A similar issue was already raised in the unity discussions, which I feel was closed inappropriately.
If a container can Resolve a particular type then it should also be able to return that it IsRegistered.
Please do be aware that using IsRegistered extensively has a negative impact on performance as looping through the Registration looking for the name and type has O(n) complexity. But that still does not justify the bug!.
I have submitted a pull request for the fix and it would be worth checking the latest comments on that to see if there are any better approaches or problems that I might have missed out with my fix!
Rahul Nath Newsletter
Join the newsletter to receive the latest updates in your inbox.