Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare a Microsoft.CodeAnalysis.ITypeSymbol to a System.Type

Tags:

c#

roslyn

I have successfully received an ITypeSymbol from a SyntaxNode by using:

SemanticModel.GetTypeInfo(sytaxNode).ConvertedType

Now I would like to know if this ITypeSymbol corresponds to a System.Type instance that is present in my executing code, like typeof(IEnumerable<int>) or someObject.GetType().

I tried

typeInfo.ConvertedType.ToString() == type.ToString()

But these do not use the same formatting rules, for instance for generics like IEnumerable<int>

TypeInfo.ToString() == "System.Collections.Generic.IEnumerable<int>"

while

typeof(IEnumerable<int>).ToString() == "System.Collections.Generic.IEnumerable`1[System.Int32]"

Moreover I think it would be better to compare AssemblyQualifiedNames in stead of just the Namespace and type name to avoid possible name clashes.

Ideally I would like to be able to get the actual System.Type instance in my executing code that corresponds to the ITypeInfo I got from the semantic model (provided that the required assembly is loaded and/or available). That would allow checking if the type is assignable from some other type etc.

like image 906
Frank Bakker Avatar asked Nov 27 '15 22:11

Frank Bakker


2 Answers

You can get the INamedTypeSymbol for a type name with Compilation.GetTypeByMetadataName().

So try this:

semanticModel.GetTypeInfo(sytaxNode).ConvertedType.Equals(
  semanticModel.Compilation.GetTypeByMetadataName(typeof(WhateverType).FullName))

This won't work with closed generic types, for those you'll need to do a bit more. For example:

var ienumerableType = semanticModel.Compilation.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1");
var intType = semanticModel.Compilation.GetTypeByMetadataName("System.Int32");
var type = ienumerableType.Construct(intType);
like image 108
Tamas Avatar answered Nov 12 '22 05:11

Tamas


Based on the answer from @Tamas, I created the following recursive solution that works for closed generic types.

    static bool TypeSymbolMatchesType(ITypeSymbol typeSymbol, Type type, SemanticModel semanticModel)
    {
        return GetTypeSymbolForType(type, semanticModel).Equals(typeSymbol);
    }

    static INamedTypeSymbol GetTypeSymbolForType(Type type, SemanticModel semanticModel)
    {

        if (!type.IsConstructedGenericType)
        {
            return semanticModel.Compilation.GetTypeByMetadataName(type.FullName);
        }

        // get all typeInfo's for the Type arguments 
        var typeArgumentsTypeInfos = type.GenericTypeArguments.Select(a => GetTypeSymbolForType(a, semanticModel));

        var openType = type.GetGenericTypeDefinition();
        var typeSymbol = semanticModel.Compilation.GetTypeByMetadataName(openType.FullName);
        return typeSymbol.Construct(typeArgumentsTypeInfos.ToArray<ITypeSymbol>());
    }
like image 6
Frank Bakker Avatar answered Nov 12 '22 05:11

Frank Bakker