Retrieving available types in current project and its references (withoult locking)

Note: this entry has moved.

One very tricky thing inside VS used to be (at least for me until I found the solution I'm about to show you) to list and work with the types defined in the project as well as its references. The problem was mainly how to properly load the types without locking the project output for compilation, as well as retrieving the types for references that could be also project references. It turns out that there is a very cool and absolutely undocumented service in VS that allows you to do just that, writing no code :)

As a general fan of the System.ComponentModel, I noticed the new System.ComponentModel.Design.ITypeDiscoveryService:

public interface ITypeDiscoveryService
{
     ICollection GetTypes(Type baseType, bool excludeGlobalTypes);
}

Intrigued by the service, I used Reflector's excelent analyze feature to find who uses it. And I got to an interesting one in the VS SDK: Microsoft.VisualStudio.Shell.Design.DynamicTypeService. Among other very interesting members, you can retrieve the aforementioned ITypeDiscoveryService for a given IVsHierarchy:

public ITypeDiscoveryService GetTypeDiscoveryService(IVsHierarchy hierarchy)

(There's also a public ITypeResolutionService GetTypeResolutionService(IVsHierarchy hierarchy) method which should also be very useful)

That looked very promising, and combined with my previous "discovery" of a way to go from a EnvDTE.Project to an IVsHierarchy, it looked like a very easy approach. So here's the code I used:

public Dictionary GetAvailableTypes(IServiceProvider provider, bool includeReferences)
{
     DynamicTypeService typeService = (DynamicTypeService)provider.GetService(typeof(DynamicTypeService));
     Debug.Assert(typeService != null, "No dynamic type service registered.");
 
     IVsHierarchy hier = VsHelper.GetCurrentHierarchy(provider);
     Debug.Assert(hier != null, "No active hierarchy is selected.");
 
     ITypeDiscoveryService discovery = typeService.GetTypeDiscoveryService(hier);
     Project dteProject = VsHelper.ToDteProject(hier);
 
     Dictionary availableTypes = new Dictionary();
     foreach (Type type in discovery.GetTypes(typeof(object), includeReferences))
     {
         // We will never allow non-public types selection, as it's terrible practice.
         if (type.IsPublic)
         {
             if (!availableTypes.ContainsKey(type.FullName))
             {
                 availableTypes.Add(type.FullName, type);
             }
         }
     }

That simple method will give you a dictionary of all the types in the current project as well as its references, without locking any files, and without you having to worry how to traverse the DTE, references, CodeModel, etc. Very cool, indeed :)

Enjoy!

No Comments