It took me a little, but yes - there is a way to find out via EnvDTE if a given class somehow inherits a given interface.
This code fragment only detects classes that inherit directly from another class that implements INotifyPropertyChanged. So before using it, one would add some recursive logic here...
<#
// 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 interfaces implemented by this class
var allInterfaces = VisualStudioHelper.GetAllCodeElementsOfType(codeClass.ImplementedInterfaces, EnvDTE.vsCMElement.vsCMElementInterface, true);
if (allInterfaces.OfType<EnvDTE.CodeInterface>()
.Any(i => i.Name == "INotifyPropertyChanged"))
{
#>Implements Interface Directly: <#= codeClass.FullName #>
<#
// find classes that derive from this code class
foreach(EnvDTE.CodeClass potentialDerivingClass in allClasses)
{
IEnumerable<string> theBases = VisualStudioHelper.GetAllCodeElementsOfType(potentialDerivingClass.Bases, EnvDTE.vsCMElement.vsCMElementClass, true).OfType<EnvDTE.CodeClass>().Select(cc => cc.FullName);
if (theBases.Any(b => b == codeClass.FullName))
{
#>Derives from implementing class: <#= potentialDerivingClass.FullName #>
<#
}
}
}
}
#>
So given a class A that implements INotifyProperty changed, a class B deriving from A and another class C deriving from B, this code would come up with classes A and B that implement INotifyPropertyChanged.
Note: Because using the EnvDTE classes is not that nice, I used a reusable template from tangible T4 Editor's free template gallery named "tangible Visual Studio Automation Helper" - that makes it much easier to use!