I'd like to get a list of all public methods in my project that are decorated using MyAttribute
using T4/EnvDTE.
I know this can be done with reflection, but I don't want to load the assembly and reflect over it in a T4 template, rather, I want to use the existing code files as the source.
The following is boilerplate code I found on the internet that gets a reference to the current project
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="System.Core.dll" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".cs" #>
<#
IServiceProvider _ServiceProvider = (IServiceProvider)Host;
if (_ServiceProvider == null)
throw new Exception("Host property returned unexpected value (null)");
EnvDTE.DTE dte = (EnvDTE.DTE)_ServiceProvider.GetService(typeof(EnvDTE.DTE));
if (dte == null)
throw new Exception("Unable to retrieve EnvDTE.DTE");
Array activeSolutionProjects = (Array)dte.ActiveSolutionProjects;
if (activeSolutionProjects == null)
throw new Exception("DTE.ActiveSolutionProjects returned null");
EnvDTE.Project dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0);
if (dteProject == null)
throw new Exception("DTE.ActiveSolutionProjects[0] returned null");
#>
I would like to confirm your plan to use EnvDTE to gain design-time information about your project's classes and methods. In my opinion it's more reliable than risking to reflect an outdated assembly of the same project.
Since you already got the current project of your solution you should now use the Visual Studio CodeModel to iterate your classes and their methods etc. I know this can be pretty annoying, but I found a free reusable .ttinclude template that provides you with methods easing the access to the CodeModel. You might want to check out tangible's T4 Editor. It's free and ships with a free template gallery that contains one named "tangible Visual Studio Automation Helper". Using this template your resulting code could look like this:
<#
// get a reference to the project of this t4 template
var project = VisualStudioHelper.CurrentProject;
// get all class items from the code model
var allClasses = VisualStudioHelper.GetAllCodeElementsOfType(project.CodeModel.CodeElements, EnvDTE.vsCMElement.vsCMElementClass, false);
// iterate all classes
foreach(EnvDTE.CodeClass codeClass in allClasses)
{
// get all methods implemented by this class
var allFunctions = VisualStudioHelper.GetAllCodeElementsOfType(codeClass.Members, EnvDTE.vsCMElement.vsCMElementFunction, false);
foreach(EnvDTE.CodeFunction function in allFunctions)
{
// get all attributes this method is decorated with
var allAttributes = VisualStudioHelper.GetAllCodeElementsOfType(function.Attributes, vsCMElement.vsCMElementAttribute, false);
// check if the System.ObsoleteAttribute is present
if (allAttributes.OfType<EnvDTE.CodeAttribute>()
.Any(att => att.FullName == "System.ObsoleteAttribute"))
{
#><#= function.FullName #>
<#
}
}
}
#>