簡體   English   中英

如何將 Roslyn 語義 model 返回的類型符號名稱與 Mono.Cecil 返回的類型符號名稱匹配?

[英]How to match type symbol names as returned by Roslyn semantic model to those returned by Mono.Cecil?

我有以下代碼:

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。 也許微軟的兩個庫能夠產生兼容的類型名稱。

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,等),必要時添加<>

  3. 將 Cecil (/) 使用的嵌套類型分隔符替換為點 (.)

  4. 也許其他一些情況...... :)

話雖如此,另一種選擇是嘗試將 map 的名稱與其 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));
        }
    }
}

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

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",
    };
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM