【问题标题】:How to match type symbol names as returned by Roslyn semantic model to those returned by Mono.Cecil?如何将 Roslyn 语义模型返回的类型符号名称与 Mono.Cecil 返回的类型符号名称匹配?
【发布时间】:2021-06-04 12:24:16
【问题描述】:

我有以下代码:

var paramDeclType = m_semanticModel.GetTypeInfo(paramDecl.Type).Type;

paramDeclType.ToString() 返回的地方

System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<int>>

我也从 Mono.Cecil 获得相同的信息 - paramDef.ParameterType.FullName 返回

System.Collections.Generic.Dictionary`2<System.String,System.Collections.Generic.List`1<System.Int32>>

我想比较来自这两个不同来源的类型名称。

如果可能,我想避免复杂的正则表达式解析。

欢迎提出想法。

附言

与此同时,我将寻找来自 Microsoft 的 Mono.Cecil 替换 - System.Reflection.Metadata。也许微软的两个库能够产生兼容的类型名称。

【问题讨论】:

    标签: c# roslyn code-analysis mono.cecil


    【解决方案1】:

    AFAIK,SRM 比 Mono.Cecil 更底层。我没有使用它来 100% 确定,但是 AFICS,在 SRM 中您需要提供自己的类型系统,这意味着,您将获得 类型令牌方法标记等,以及如何在程序中表示它取决于您(这看起来比使用 Cecil 复杂得多)。 (您可以查看 ILSpy 代码https://github.com/icsharpcode/ILSpy/tree/master/ICSharpCode.Decompiler 了解一下)

    我不认为从 Roslyn 名称转换为 Cecil 名称有那么难(当然,取决于您的需要)。你可以试试:

    1. 看看是否可以让 Roslyn 始终使用 BLC 类型名称(而不是 C# 原始类型名称)

    2. 删除排名信息(1, 2 等),如有必要可能添加

    3. 将 Cecil (/) 使用的嵌套类型分隔符替换为点 (.)

    4. 也许还有一些其他情况...... :)

    话虽如此,另一种选择是尝试将名称映射到其 System.Type 等效项;一旦你有了一个 System.Type,你就可以在 Cecil 中调用 Module.Import() 并返回一个 TypeReference 并比较它的全名(不幸的是不能通过相等来比较两个 TypeReferences)。

    Obs:尝试将此添加为评论,但它太长:)

    您可以使用类似于以下代码的内容来找出完全限定的类型名称:

    using System;
    using System.Linq;
    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.CSharp;
    using Microsoft.CodeAnalysis.CSharp.Syntax;
    
    namespace ConsoleApplication
    {
        class Program
        {
            static void Main(string[] args)
            {
                var st = CSharpSyntaxTree.ParseText("class Foo { int i; }");
                var v = st.GetRoot().DescendantNodesAndSelf().OfType<VariableDeclarationSyntax>().Single().Type;
                var pts = (PredefinedTypeSyntax) v;
    
                var Mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
                var compilation = CSharpCompilation.Create("MyCompilation", syntaxTrees: new[] { st }, references: new[] { Mscorlib });
                var model = compilation.GetSemanticModel(st);
    
                var symbol = model.GetTypeInfo(pts);
    
                System.Console.WriteLine(symbol.Type.ContainingNamespace.Name + "." + symbol.Type.Name);
                
                // or even something like...
                var intType = model.Compilation.GetTypeByMetadataName(typeof(int).FullName);
                Console.WriteLine(v.ToString() + "  " + v.GetType().FullName + " " + (symbol.Type.SpecialType == intType.SpecialType));
            }
        }
    }
    

    【讨论】:

    • 我使用了正则表达式。它确实并不复杂,尽管我希望避免它。 SRM 看起来确实很难。至于您的建议 - 我没有找到如何让 Roslyn 使用 BLC 类型名称。
    【解决方案2】:

    我想分享一下我目前使用的功能:

    private const string GENERIC_ARG_COUNT_PATTERN = @"`\d+";
    private static readonly Regex s_genericArgCountRegex = new Regex(GENERIC_ARG_COUNT_PATTERN);
    
    
    public static bool IsSameType(this TypeReference typeRef, ITypeSymbol typeSymbol, bool isByRef)
    {
        if (isByRef || typeRef.IsByReference)
        {
            return isByRef && typeRef.IsByReference && DoIsSameType(((ByReferenceType)typeRef).ElementType, typeSymbol);
        }
    
        return DoIsSameType(typeRef, typeSymbol);
    
        static bool DoIsSameType(TypeReference typeRef, ITypeSymbol typeSymbol)
        {
            var arrayTypeSymbol = typeSymbol as IArrayTypeSymbol;
            var arrayTypeRef = typeRef as ArrayType;
            if (arrayTypeSymbol != null || arrayTypeRef != null)
            {
                return arrayTypeSymbol != null
                    && arrayTypeRef != null
                    && arrayTypeSymbol.Rank == arrayTypeRef.Rank
                    && DoIsSameType(arrayTypeRef.ElementType, arrayTypeSymbol.ElementType);
            }
    
            // Optimistic approach
            var declFullName = typeSymbol.ToString();
            var typeRefFullName = typeRef.FullName;
            if (typeRefFullName.Contains('`'))
            {
                typeRefFullName = s_genericArgCountRegex.Replace(typeRef.FullName, "");
            }
            if (declFullName == typeRefFullName)
            {
                return true;
            }
    
            // Built-in types - either top level or as generic arguments.
            if (typeRef is GenericInstanceType genTypeRef)
            {
                if (!(typeSymbol is INamedTypeSymbol namedTypeSymbol) ||
                    !namedTypeSymbol.IsGenericType ||
                    genTypeRef.ElementType.Name != namedTypeSymbol.ConstructedFrom.MetadataName ||
                    genTypeRef.GenericArguments.Count != namedTypeSymbol.TypeArguments.Length ||
                    genTypeRef.ElementType.Namespace != namedTypeSymbol.ConstructedFrom.ContainingNamespace.ToString())
                {
                    return false;
                }
                for (int i = 0; i < genTypeRef.GenericArguments.Count; ++i)
                {
                    if (!DoIsSameType(genTypeRef.GenericArguments[i], namedTypeSymbol.TypeArguments[i]))
                    {
                        return false;
                    }
                }
                return true;
            }
    
            return
                typeRef.Name == typeSymbol.Name &&
                typeRef.IsBuiltInType() &&
                typeSymbol.ContainingNamespace.Name == "System";
        }
    }
    
    public static bool IsBuiltInType(this TypeReference t)
    {
        return t.Scope.Name == "mscorlib" && DoIsBuiltInType(t);
    
        static bool DoIsBuiltInType(TypeReference t) => t switch
        {
            ArrayType arrayType => DoIsBuiltInType(arrayType.ElementType),
            ByReferenceType byReferenceType => DoIsBuiltInType(byReferenceType.ElementType),
            _ => t.IsPrimitive || t.Name == "Object" || t.Name == "Decimal" || t.Name == "String",
        };
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-29
      • 1970-01-01
      • 2015-12-18
      相关资源
      最近更新 更多