类型系统详解
简介
本文档详细介绍 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}");
}
}