使用 roslyn 确定基元类型

本文关键字:类型 roslyn 使用 | 更新日期: 2023-09-27 18:30:31

使用 Roslyn,如何确定ITypeSymbol是否是基元类型?

ITypeSymbol没有像Type.IsPrimitive那样的IsPrimitive属性

有没有办法将ITypeSymbol转换为类型或其他方法来确定ITypeSymbol是否为基元类型?

使用 roslyn 确定基元类型

看起来像是

用于确定的代码在 TypedConstant 类中,但它是内部的,我找不到一个可以很好地让我到达那里的公共 API。我最终将该方法复制到我的项目中。

    /// <remarks>
    /// TypedConstant isn't computing its own kind from the type symbol because it doesn't
    /// have a way to recognize the well-known type System.Type.
    /// </remarks>
    internal static TypedConstantKind GetTypedConstantKind(ITypeSymbol type, Compilation compilation)
    {
        Debug.Assert(type != null);
        switch (type.SpecialType)
        {
            case SpecialType.System_Boolean:
            case SpecialType.System_SByte:
            case SpecialType.System_Int16:
            case SpecialType.System_Int32:
            case SpecialType.System_Int64:
            case SpecialType.System_Byte:
            case SpecialType.System_UInt16:
            case SpecialType.System_UInt32:
            case SpecialType.System_UInt64:
            case SpecialType.System_Single:
            case SpecialType.System_Double:
            case SpecialType.System_Char:
            case SpecialType.System_String:
            case SpecialType.System_Object:
                return TypedConstantKind.Primitive;
            default:
                switch (type.TypeKind)
                {
                    case TypeKind.Array:
                        return TypedConstantKind.Array;
                    case TypeKind.Enum:
                        return TypedConstantKind.Enum;
                    case TypeKind.Error:
                        return TypedConstantKind.Error;
                }
                if (compilation != null &&
                    compilation.IsSystemTypeReference(type))
                {
                    return TypedConstantKind.Type;
                }
                return TypedConstantKind.Error;
        }
    }

类型是否为基元取决于您的语言。在 C# 中,DateTime 不是基元,但它在 VB 中。由于 ITypeSymbol 用于两种语言,因此它没有特定于语言的属性。

尝试以下扩展方法:

    //eg: symbol.IsFullNameEquals("List`1", "Generic", "Collections", "System")
    internal static bool IsFullNameEquals(this ISymbol symbol, params string[] nameParts) {
        if (symbol == null) throw new ArgumentNullException("symbol");
        if (nameParts == null || nameParts.Length == 0) throw new ArgumentNullException("nameParts");
        var idx = 0;
        for (; symbol != null; symbol = symbol.ContainingSymbol) {
            var name = symbol.MetadataName;
            if (string.IsNullOrEmpty(name)) break;
            if (idx == nameParts.Length) return false;
            if (name != nameParts[idx]) return false;
            idx++;
        }
        return idx == nameParts.Length;
    }
    //eg: var idx = symbol.MatchFullName(new []{"List`1", "Dictionary`2"}, new []{"Generic", "Collections", "System"});
    //return value: -1: none; 0: symbol is List`1; 1: symbol is Dictionary`2 
    internal static int MatchFullName(this ISymbol symbol, string[] typeNames, string[] outerNameParts) {
        if (symbol == null) throw new ArgumentNullException("symbol");
        if (typeNames == null || typeNames.Length == 0) throw new ArgumentNullException("typeNames");
        var fullLength = 1 + (outerNameParts != null ? outerNameParts.Length : 0);
        int idx = 0, result = -1;
        for (; symbol != null; symbol = symbol.ContainingSymbol) {
            var name = symbol.MetadataName;
            if (string.IsNullOrEmpty(name)) break;
            if (idx == fullLength) return -1;
            if (idx == 0) {
                for (var i = 0; i < typeNames.Length; i++) {
                    if (name == typeNames[i]) {
                        result = i;
                        break;
                    }
                }
                if (result == -1) return -1;
            }
            else {
                if (name != outerNameParts[idx - 1]) return -1;
            }
            idx++;
        }
        if (idx == fullLength) return result;
        return -1;
    }