Getting type from a symbol in roslyn

antiskidwarpdrive picture antiskidwarpdrive · Jan 12, 2016 · Viewed 9k times · Source

What is the best general purpose way to get a System.Type from Microsoft.CodeAnalysis.ISymbol for different types of symbols ? (e.g. class declarations, variable, properties, etc)

I want to be able to do various checks on the type e.g. as checking if the type implements any interface or is cast-able to any interface, just like one can check on System.Type.

The problem I am having is that most of the concrete classes used to represent the symbol are internal (see http://sourceroslyn.io/) and I could not find tye type information in the ISymbol.

  • SourceNamedTypeSymbol
  • LocalSymbol

I retrieve the ISymbol using the following code

var objectSymbol = (ISymbol)model.GetDeclaredSymbol(obj.Node);

Answer

Jeroen Vannevel picture Jeroen Vannevel · Jan 12, 2016

Short answer: you can't. There is no proper way to get a System.Type (reflection) from an ISymbol (Roslyn).

One option to do go in the direction you want is constructing the fully-qualified name of your type and then looking that up through reflection (example).

You should probably ask yourself whether this is something you need to do in the first place though -- reflection and Roslyn aren't really intended to work together.

What you are interested in, however, can be done through Roslyn as well. The key here is using the semantic model which has all this information for you. All declarations (opposed to usages) have a specific overload available that allows you to get the declaring symbol and return it in the appropriate type (such as INamedTypeSymbol in this case).

Take the following example:

const string source = @"
using System;

namespace MyNamespace 
{
    class MyClass : IDisposable
    {
        void Method()
        {
            MyClass nameOfVariable, another;
        }
    }
}
";
var tree = CSharpSyntaxTree.ParseText(source);
var compilation = CSharpCompilation.Create("MyCompilation", new[] { tree }, new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
var semanticModel = compilation.GetSemanticModel(tree);
var root = tree.GetRoot();

var classSymbol = semanticModel.GetDeclaredSymbol(root.DescendantNodes().OfType<ClassDeclarationSyntax>().First());
Console.WriteLine(string.Join(", ", classSymbol.AllInterfaces));

This will display all the interfaces the class implements. Keep in mind however that this just refers to the current definition -- if you're also interested in base types you'll have to go through the hierarchy yourself.

In your scenario you should be able to just cast it to the right type (assuming you are checking a declaration node):

var objectSymbol = (INamedTypeSymbol) model.GetDeclaredSymbol(obj.Node);