Finding Interfaces implemented in a Class
-
Monday, April 30, 2012 1:48 PM
I want to find out what Interfaces a ClassTypeDecl implements. I'm thinking that this is best done with a Semantic call. I want to find if a class implements a specific Interface.
There is a caveat - I need this to work if the Interface is defined 'in-class' or in a base class??
All Replies
-
Monday, April 30, 2012 3:29 PM
Yes, using semantics is the right thing to do here. If you create a semantic model for a syntax tree, you can then ask it for a NamedTypeSymbol for a ClassDeclarationSyntax (I'm not sure what ClassTypeDecl is). And this NamedTypeSymbol then has a property AllInterfaces which will give you symbols for all the interfaces this class implements, including interfaces implemented though base classes or through other interfaces.
For example like this:
string code = @" interface IFoo {} interface IBar {} class Foo : IFoo {} class Bar : Foo, IBar {}"; var tree = SyntaxTree.ParseCompilationUnit(code); var bar = tree.Root.DescendentNodes().OfType<ClassDeclarationSyntax>().Last(); var compilation = Compilation.Create("foo") .AddSyntaxTrees(tree); var semanticModel = compilation.GetSemanticModel(tree); var barSymbol = semanticModel.GetDeclaredSymbol(bar); var interfaces = barSymbol.AllInterfaces; // contains IFoo and IBar
- Proposed As Answer by Shyam NamboodiripadMicrosoft Employee, Owner Tuesday, May 01, 2012 6:54 PM
-
Tuesday, May 01, 2012 8:28 PM
Hi,
Many thanks for the input on this I've got a work around at the moment but I am not happy with it. It basically checks what the basetype is and if its the one I am after I run with that. Of course in real life I will not know how deep the Interface I won't could potentially be so I really want my code to work like the example posted. I've run the above code and it works just as I would expect. This leaves me a little puzzled as to why the following is not working -:
string code = @" public class ViewModelBase : INotifyPropertyChanged { #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion }"; // @" // interface IFoo // {} // // interface IBar // {} // // class Foo : IFoo // {} // // class Bar : Foo, IBar // {}"; var tree = SyntaxTree.ParseCompilationUnit(code); var bar = tree.Root.DescendentNodes().OfType<ClassDeclarationSyntax>().Last(); var compilation = Compilation.Create("foo").AddSyntaxTrees(tree).AddReference(new AssemblyFileReference(typeof(System.ComponentModel.INotifyPropertyChanged).Assembly.Location)); var semanticModel = compilation.GetSemanticModel(tree); var barSymbol = semanticModel.GetDeclaredSymbol(bar); var interfaces = barSymbol.AllInterfaces; // contains IFoo and IBarThe above is pretty much the same as the previous example but with a small class implementing the interface INotifyPropertyChanged. It also adds the assemblies required to know about INotifyPropertyChanged.
This returns me an empty set for 'interfaces'.... Whats up?
-
Tuesday, May 01, 2012 9:05 PM
I think you're missing
using System.ComponentModel;
before declaring ViewModelBase.
You can use compilation.GetDiagnostics() to see whether the compilation contains any errors or warnings.
-
Wednesday, May 02, 2012 8:50 AM
svick - thanks for helping me with this. Adding the using to the code string the posted above solved the issue. Thanks for the tip on GetDiagnostics - I'll remember that for compilations.
There is a very weird problem. I am iterating through a solution and its associated projects , looking for projects containing C# files and then trying to see if that file implements the interface I'm interested. When I inline the compilation (ie I don't call out to a function to do the compilation) it fails to find the interfaces. Yet when I implement the interface finding code as a method it works well/flawlessly!
As a work around - I've implemented the following private method -:
private bool LookForInterface(string fileContents, string interfaceName, out List<ClassDeclarationsSyntax> aListOfSyntax);
When calling this method its behaving as I want it and would expect. Weirdly if inline this code (ie instead of calling the private method) it returns zero for the interfaces. Because I've been getting so much help from people on here I'm going to try and replicate this in a small project - if I can replicate then I'll post it up.
Rich
-
Wednesday, May 02, 2012 9:15 AMAre you sure that's what's actually happening and not just what you see in the debugger? I had some issues with Roslyn where the Visual Studio debugger showed a collection as empty, but it actually contained some elements. Maybe this is a similar issue?
-
Wednesday, May 02, 2012 10:57 AM
svick, I was tempted to think that and yes I have seen LOTS of issues like this. My situation is that I am debugging via VS2010 when a plugin is loaded into Expression Blend.
The plugin contains the Roslyn code.
This seems to be causing a lot of threading issues and sometimes I am simply losing context within a Debuging phase. :(
However I have done things like set up conditions to see if my code is ever hit should it encounter ANY interfaces. Code such as -:
var Interfaces = barSymbol.AllInterfaces; foreach(var interfaceFound in Interfaces) { //PUT A BREAKPOINT ON THIS LINE Debug.Writeline("WOO HOO - we found an interface!"); }And I don't see it. Ever. So something odd is going on.

