Get All Types in an Assembly
Sometimes, you need to scan all the types in an assembly for a certain reason. For example, ASP.NET MVC does this to look for potential controllers.
One naïve implementation is to simply call Assembly.GetTypes()
and hope for the best. But there’s a problem with this. As Suzanne Cook points out,
If a type can’t be loaded for some reason during a call to
Module.GetTypes()
,ReflectionTypeLoadException
will be thrown.Assembly.GetTypes()
also throws this because it callsModule.GetTypes()
.
In other words, if any type can’t be loaded, the entire method call blows up and you get zilch.
There’s multiple reason why a type can’t be loaded. Here’s one example:
public class Foo : Bar // Bar defined in another unavailable assembly
{
}
The class Foo
derives from a class Bar
, but Bar
is defined in another assembly. Here’s a non-exhaustive list of reasons why loading Foo
might fail:
- The assembly containing
Bar
does not exist on disk. - The current user does not have permission to load the assembly
containing
Bar
. - The assembly containing
Bar
is corrupted and not a valid assembly.
Once again, for more details check out Suzanne’s blog post on Debugging Assembly Loading Failures.
Solution
As you might expect, being able to get a list of types, even if you don’t plan on instantiating instances of them, is a common and important task. Fortunately, the ReflectionTypeLoadException
thrown when a type can’t be loaded contains all the information you need. Here’s an example of ASP.NET MVC taking advantage of this within the internal TypeCacheUtil
class (there’s a lot of other great code nuggets if you look around the source
code)
Type[] typesInAsm;
try
{
typesInAsm = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
typesInAsm = ex.Types;
}
This would be more useful as a generic extension method. Well the estimable Jon Skeet has you covered in this StackOverflow answer (slightly edited to add in parameter validation):
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
{
if (assembly == null) throw new ArgumentNullException(nameof(assembly));
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null);
}
}
I’ve found this code to be extremely useful many times.
Comments
10 responses