Daniel Cazzulino's Blog : Retrieving available types in current project and its references (withoult locking)

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

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!

posted on Friday, January 06, 2006 8:47 PM by kzu

# re: Retrieving available types in current project and its references (withoult locking) @ Saturday, January 21, 2006 11:27 PM

Hi

I am trying to build a CustomControl, one of the property is "ReferencedAssemblies" in the project (Current Project where control is being used). I want to display all the referenced properties as default properties.


Here is the code that I wrote and it is not working. Can you tell me why and let me a easier way of doing if any!

Thanks
Venkat

public class MyTextBox : System.Web.UI.WebControls.TextBox
{
private string cReferencedAssemblies = "";

[Category("Data"),
Description("The Referenced Assemblies ,
DefaultValue(""), TypeConverter(typeof(CustomRefAssembliesConv))]
public string ReferencedAssemblies
{
get { return this.cReferencedAssemblies; }
set { this.cReferencedAssemblies = value; }
}



}





















internal class CustomRefAssembliesConv :StringConverter {

public override bool GetStandardValuesSupported(
ITypeDescriptorContext context)
{
return true;
}

public override bool GetStandardValuesExclusive(
ITypeDescriptorContext context)
{
// returning false here means the property will
// have a drop down and a value that can be manually
// entered.
return false;
}

public override StandardValuesCollection GetStandardValues(
ITypeDescriptorContext context)
{
//DTE2 dte = (DTE2)context.GetService(typeof(DTE2));

MyTextBox zTextBox = (MyTextBox)context.Instance;
ISite ZSite = zTextBox.Site;
DTE dte = (DTE)ZSite.GetService(typeof(DTE));
Array activeProjects = (Array)dte.ActiveSolutionProjects;


Project selectedProject = (Project)activeProjects.GetValue(0);

VSProject selectedVSProject = (VSProject)selectedProject.Object;
References projreferences = selectedVSProject.References;

string[] editorObjects = new string[projreferences.Count];
int editObjectLength = 0;
foreach (Reference prjref in projreferences)
{
editorObjects[editObjectLength] = prjref.Name;
editObjectLength++;

}



StandardValuesCollection defaultval = new StandardValuesCollection(editorObjects);
return defaultval;







}

}

Venkat

# re: Retrieving available types in current project and its references (withoult locking) @ Thursday, April 20, 2006 9:26 AM

This was something I needed myself, so thanks for posting it.

However, there are some cases where it fails. In particular, if you have a designer or editor open when the project is opening, their is no selectedItems[1] available.

Now, you usually wouldn't need to grab this information so quickly or without "proper" context, but it delays getting a reference to the services functionality, so that it has to be queried again until there is an acceptable context.

I got around it by overloading the function with a prepopulated IvsHierarchy argument(which is passed to editors when they are opening).

Just an FYI.

Jonathan Davlin

# How to get a System.Type from an EnvDTE.CodeTypeRef or EnvDTE.CodeClass @ Thursday, October 04, 2007 1:35 PM

I have already hinted at this in a previous post , but this time it's a bit different. Sometimes it's

Anonymous

# How do I get a System.Type from a type name? @ Thursday, March 06, 2008 4:49 AM

This another question that appears from time to time in the forums, and it is one extremely complicated

Anonymous