19

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);
Kirill Osenkov
  • 8,786
  • 2
  • 33
  • 37
antiskidwarpdrive
  • 321
  • 1
  • 2
  • 8

2 Answers2

28

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);
Community
  • 1
  • 1
Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
  • Thanks for the reply and I was able to achieve the result ! – antiskidwarpdrive Jan 12 '16 at 16:18
  • 9
    And to highlight why there is no easy way: it's entirely possible you can't actually get one. The only way you can get a System.Type is to have reflection loaded the assembly in question, but you might not actually have a loadable assembly in the first place. Fundamentally Reflection is a runtime API, and runtime and compile time are different things. You're best off always using Roslyn APIs, as Jeroen's fantastic answer describes. – Jason Malinowski Jan 12 '16 at 22:37
  • It seems like it might actually be possible to get an partial/approximate `System.Type` from `ITypeSymbol`: See https://github.com/dotnet/runtime/blob/main/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs#L12. It does involve a LOT of code and I'm not sure what the limitations are, but perhaps this could be made available as a stand-alone library. – extremeandy Feb 24 '22 at 23:57
3

I think this is what you are looking for:

var castedProperty = (IPropertySymbol) property;
var type = castedProperty.Type.Name;

The variable 'property' is an ISymbol instance.

Pang
  • 9,564
  • 146
  • 81
  • 122