Skip to content

类型系统详解

简介

本文档详细介绍 INamedTypeSymbol(命名类型符号),包括类型系统、泛型处理、继承关系和特殊类型。

适合人群: 中级开发者
预计阅读时间: 45 分钟
前置知识: 语法树基础、符号系统、语义模型基础


📋 本文导航

章节难度阅读时间链接
核心属性🟢10 分钟查看
泛型类型处理🟡15 分钟查看
继承和接口🟡15 分钟查看
特殊类型处理🟢10 分钟查看

返回: 主文档 | 下一篇: 方法分析详解


🟢 核心属性

INamedTypeSymbol 表示命名类型,包括类(class)、结构(struct)、接口(interface)、枚举(enum)、委托(delegate)和记录(record)。

基本信息属性

csharp
INamedTypeSymbol typeSymbol;

// 类型名称
string name = typeSymbol.Name;

// 类型种类(Class, Struct, Interface, Enum, Delegate)
TypeKind typeKind = typeSymbol.TypeKind;

// 特殊类型(System.Object, System.String 等)
SpecialType specialType = typeSymbol.SpecialType;

// 是否是引用类型
bool isReferenceType = typeSymbol.IsReferenceType;

// 是否是值类型
bool isValueType = typeSymbol.IsValueType;

// 是否是记录类型(C# 9+)
bool isRecord = typeSymbol.IsRecord;

// 访问修饰符
Accessibility accessibility = typeSymbol.DeclaredAccessibility;

// 是否是抽象类型
bool isAbstract = typeSymbol.IsAbstract;

// 是否是密封类型
bool isSealed = typeSymbol.IsSealed;

// 是否是静态类型
bool isStatic = typeSymbol.IsStatic;

成员访问属性

csharp
// 获取所有成员
ImmutableArray<ISymbol> allMembers = typeSymbol.GetMembers();

// 按名称获取成员
ImmutableArray<ISymbol> membersByName = typeSymbol.GetMembers("PropertyName");

// 获取所有类型成员(嵌套类型)
ImmutableArray<INamedTypeSymbol> nestedTypes = typeSymbol.GetTypeMembers();

// 获取构造函数
ImmutableArray<IMethodSymbol> constructors = typeSymbol.Constructors;

// 获取实例构造函数
ImmutableArray<IMethodSymbol> instanceConstructors = typeSymbol.InstanceConstructors;

// 获取静态构造函数
ImmutableArray<IMethodSymbol> staticConstructors = typeSymbol.StaticConstructors;

提示

使用 GetMembers() 获取所有成员,使用 GetMembers(name) 按名称过滤成员。

示例:分析类型基本信息

csharp
public void AnalyzeTypeBasicInfo(INamedTypeSymbol typeSymbol)
{
    Console.WriteLine($"类型名称: {typeSymbol.Name}");
    Console.WriteLine($"完整名称: {typeSymbol.ToDisplayString()}");
    Console.WriteLine($"类型种类: {typeSymbol.TypeKind}");
    Console.WriteLine($"访问修饰符: {typeSymbol.DeclaredAccessibility}");
    
    // 检查类型特性
    if (typeSymbol.IsAbstract)
        Console.WriteLine("这是一个抽象类型");
    if (typeSymbol.IsSealed)
        Console.WriteLine("这是一个密封类型");
    if (typeSymbol.IsStatic)
        Console.WriteLine("这是一个静态类型");
    if (typeSymbol.IsRecord)
        Console.WriteLine("这是一个记录类型");
    
    // 列出所有成员
    Console.WriteLine($"\n成员列表 ({typeSymbol.GetMembers().Length} 个):");
    foreach (var member in typeSymbol.GetMembers())
    {
        Console.WriteLine($"  - {member.Kind}: {member.Name}");
    }
}

🟡 泛型类型处理

泛型是 C# 中的重要特性,Roslyn 提供了丰富的 API 来处理泛型类型。

开放泛型 vs 封闭泛型

开放泛型(Open Generic):包含未绑定的类型参数,如 List<T>
封闭泛型(Closed Generic):所有类型参数都已绑定,如 List<int>

csharp
// 检查是否是泛型类型
bool isGeneric = typeSymbol.IsGenericType;

// 检查是否是未绑定的泛型类型
bool isUnboundGeneric = typeSymbol.IsUnboundGenericType;

// 获取类型参数
ImmutableArray<ITypeParameterSymbol> typeParameters = typeSymbol.TypeParameters;

// 获取类型实参
ImmutableArray<ITypeSymbol> typeArguments = typeSymbol.TypeArguments;

// 获取原始泛型定义
INamedTypeSymbol originalDefinition = typeSymbol.OriginalDefinition;

// 获取泛型参数数量
int arity = typeSymbol.Arity;

示例:区分开放和封闭泛型

csharp
public void AnalyzeGenericType(INamedTypeSymbol typeSymbol)
{
    if (!typeSymbol.IsGenericType)
    {
        Console.WriteLine("这不是泛型类型");
        return;
    }
    
    Console.WriteLine($"泛型类型: {typeSymbol.ToDisplayString()}");
    Console.WriteLine($"泛型参数数量: {typeSymbol.Arity}");
    
    if (typeSymbol.IsUnboundGenericType)
    {
        Console.WriteLine("这是开放泛型类型");
        Console.WriteLine("类型参数:");
        foreach (var typeParam in typeSymbol.TypeParameters)
        {
            Console.WriteLine($"  - {typeParam.Name}");
        }
    }
    else
    {
        Console.WriteLine("这是封闭泛型类型");
        Console.WriteLine("类型实参:");
        foreach (var typeArg in typeSymbol.TypeArguments)
        {
            Console.WriteLine($"  - {typeArg.ToDisplayString()}");
        }
    }
}

注意

比较泛型类型时,应该使用 OriginalDefinition 来比较泛型定义,而不是直接比较类型实例。

类型参数和类型实参

csharp
// 示例:List<int>
// - List<T> 是原始定义
// - T 是类型参数(TypeParameter)
// - int 是类型实参(TypeArgument)

public void AnalyzeTypeParametersAndArguments(INamedTypeSymbol typeSymbol)
{
    if (typeSymbol.IsGenericType)
    {
        // 获取原始定义(List<T>)
        var originalDef = typeSymbol.OriginalDefinition;
        Console.WriteLine($"原始定义: {originalDef.ToDisplayString()}");
        
        // 类型参数(T)
        foreach (var typeParam in originalDef.TypeParameters)
        {
            Console.WriteLine($"类型参数: {typeParam.Name}");
            
            // 类型参数约束
            if (typeParam.HasReferenceTypeConstraint)
                Console.WriteLine("  - 约束: class");
            if (typeParam.HasValueTypeConstraint)
                Console.WriteLine("  - 约束: struct");
            if (typeParam.HasConstructorConstraint)
                Console.WriteLine("  - 约束: new()");
        }
        
        // 类型实参(int)
        if (!typeSymbol.IsUnboundGenericType)
        {
            for (int i = 0; i < typeSymbol.TypeArguments.Length; i++)
            {
                Console.WriteLine($"类型实参 {i}: {typeSymbol.TypeArguments[i].ToDisplayString()}");
            }
        }
    }
}

泛型类型构造

使用 Construct 方法可以从开放泛型创建封闭泛型:

csharp
public INamedTypeSymbol ConstructGenericType(
    INamedTypeSymbol openGenericType,
    params ITypeSymbol[] typeArguments)
{
    // 例如:从 List<T> 构造 List<int>
    return openGenericType.Construct(typeArguments);
}

// 使用示例
public void Example(Compilation compilation)
{
    // 获取 List<T> 的符号
    var listType = compilation.GetTypeByMetadataName("System.Collections.Generic.List`1");
    
    // 获取 int 的符号
    var intType = compilation.GetSpecialType(SpecialType.System_Int32);
    
    // 构造 List<int>
    var listOfInt = listType.Construct(intType);
    
    Console.WriteLine(listOfInt.ToDisplayString()); // 输出: System.Collections.Generic.List<int>
}

🟡 继承和接口

类型的继承关系和接口实现是面向对象编程的核心概念。

基类访问

csharp
// 获取基类
INamedTypeSymbol baseType = typeSymbol.BaseType;

// 检查是否有基类
bool hasBaseType = typeSymbol.BaseType != null;

// 获取所有基类(包括 Object)
public IEnumerable<INamedTypeSymbol> GetAllBaseTypes(INamedTypeSymbol typeSymbol)
{
    var current = typeSymbol.BaseType;
    while (current != null)
    {
        yield return current;
        current = current.BaseType;
    }
}

接口实现

csharp
// 获取直接实现的接口
ImmutableArray<INamedTypeSymbol> interfaces = typeSymbol.Interfaces;

// 获取所有接口(包括继承的)
ImmutableArray<INamedTypeSymbol> allInterfaces = typeSymbol.AllInterfaces;

// 检查是否实现了特定接口
public bool ImplementsInterface(INamedTypeSymbol typeSymbol, INamedTypeSymbol interfaceSymbol)
{
    return typeSymbol.AllInterfaces.Contains(
        interfaceSymbol,
        SymbolEqualityComparer.Default);
}

示例:分析继承链

点击查看完整示例:遍历继承链
csharp
public void AnalyzeInheritanceChain(INamedTypeSymbol typeSymbol)
{
    Console.WriteLine($"分析类型: {typeSymbol.ToDisplayString()}");
    
    // 1. 分析基类链
    Console.WriteLine("\n继承链:");
    var current = typeSymbol;
    int level = 0;
    while (current != null)
    {
        var indent = new string(' ', level * 2);
        Console.WriteLine($"{indent}{current.ToDisplayString()}");
        current = current.BaseType;
        level++;
    }
    
    // 2. 分析接口实现
    Console.WriteLine("\n直接实现的接口:");
    foreach (var iface in typeSymbol.Interfaces)
    {
        Console.WriteLine($"  - {iface.ToDisplayString()}");
    }
    
    Console.WriteLine("\n所有接口(包括继承的):");
    foreach (var iface in typeSymbol.AllInterfaces)
    {
        Console.WriteLine($"  - {iface.ToDisplayString()}");
    }
    
    // 3. 检查是否派生自特定类型
    var objectType = typeSymbol.BaseType;
    while (objectType?.BaseType != null)
    {
        objectType = objectType.BaseType;
    }
    
    if (objectType != null)
    {
        Console.WriteLine($"\n最终基类: {objectType.ToDisplayString()}");
    }
}

关键要点:

  • 使用 BaseType 属性遍历继承链
  • 使用 Interfaces 获取直接实现的接口
  • 使用 AllInterfaces 获取所有接口(包括继承的)
  • 始终检查 BaseType 是否为 null

提示

使用 SymbolEqualityComparer.Default 来比较符号,而不是使用 == 运算符。


🟢 特殊类型处理

C# 中有一些特殊的类型需要特别处理。

枚举类型

csharp
public void AnalyzeEnumType(INamedTypeSymbol typeSymbol)
{
    if (typeSymbol.TypeKind != TypeKind.Enum)
        return;
    
    Console.WriteLine($"枚举类型: {typeSymbol.Name}");
    
    // 获取枚举的基础类型
    INamedTypeSymbol underlyingType = typeSymbol.EnumUnderlyingType;
    Console.WriteLine($"基础类型: {underlyingType.ToDisplayString()}");
    
    // 获取枚举成员
    var enumMembers = typeSymbol.GetMembers()
        .OfType<IFieldSymbol>()
        .Where(f => f.IsConst);
    
    Console.WriteLine("枚举成员:");
    foreach (var member in enumMembers)
    {
        Console.WriteLine($"  - {member.Name} = {member.ConstantValue}");
    }
}

委托类型

csharp
public void AnalyzeDelegateType(INamedTypeSymbol typeSymbol)
{
    if (typeSymbol.TypeKind != TypeKind.Delegate)
        return;
    
    Console.WriteLine($"委托类型: {typeSymbol.Name}");
    
    // 获取 Invoke 方法
    var invokeMethod = typeSymbol.DelegateInvokeMethod;
    
    if (invokeMethod != null)
    {
        Console.WriteLine($"返回类型: {invokeMethod.ReturnType.ToDisplayString()}");
        Console.WriteLine("参数:");
        foreach (var param in invokeMethod.Parameters)
        {
            Console.WriteLine($"  - {param.Type.ToDisplayString()} {param.Name}");
        }
    }
}

记录类型

csharp
public void AnalyzeRecordType(INamedTypeSymbol typeSymbol)
{
    if (!typeSymbol.IsRecord)
        return;
    
    Console.WriteLine($"记录类型: {typeSymbol.Name}");
    
    // 检查是记录类还是记录结构
    if (typeSymbol.IsReferenceType)
        Console.WriteLine("类型: 记录类 (record class)");
    else
        Console.WriteLine("类型: 记录结构 (record struct)");
    
    // 记录类型通常有编译器生成的成员
    var properties = typeSymbol.GetMembers()
        .OfType<IPropertySymbol>();
    
    Console.WriteLine("属性:");
    foreach (var prop in properties)
    {
        Console.WriteLine($"  - {prop.Type.ToDisplayString()} {prop.Name}");
    }
}

元组类型

csharp
public void AnalyzeTupleType(ITypeSymbol typeSymbol)
{
    if (!typeSymbol.IsTupleType)
        return;
    
    var tupleType = (INamedTypeSymbol)typeSymbol;
    Console.WriteLine($"元组类型: {tupleType.ToDisplayString()}");
    
    // 获取元组元素
    var tupleElements = tupleType.TupleElements;
    Console.WriteLine($"元素数量: {tupleElements.Length}");
    
    for (int i = 0; i < tupleElements.Length; i++)
    {
        var element = tupleElements[i];
        Console.WriteLine($"  元素 {i}: {element.Type.ToDisplayString()} {element.Name}");
    }
}

🔗 相关 API


📚 下一步

基于 MIT 许可发布