语义模型 API:类型和方法符号
📋 文档信息
难度: 🟡 中级
预计阅读时间: 30 分钟
前置知识: 语法树基础、符号系统、语义模型基础
适合人群: 中级开发者,需要深入理解类型和方法分析
📋 快速导航
| 章节 | 难度 | 阅读时间 | 链接 |
|---|---|---|---|
| 概览 | 🟢 | 5 分钟 | 查看 |
| 快速开始示例 | 🟢 | 10 分钟 | 查看 |
| API 速查表 | 🟢 | 5 分钟 | 查看 |
| 深入学习 | - | - | 查看 |
深入学习主题
| 主题 | 难度 | 阅读时间 | 文档链接 |
|---|---|---|---|
| 类型系统详解 | 🟡 | 45 分钟 | semantic-model-types.md |
| 方法分析详解 | 🟡 | 45 分钟 | semantic-model-methods.md |
| 实战示例和最佳实践 | 🟡 | 40 分钟 | semantic-model-type-examples.md |
🎯 概览
在 Roslyn 中,符号(Symbol) 是对代码元素的语义表示。类型符号和方法符号是最常用的两种符号:
INamedTypeSymbol(命名类型符号):
- 表示类、结构、接口、枚举、委托、记录等命名类型
- 提供类型的完整元数据:继承关系、成员、泛型参数等
- 用于类型分析、代码生成、重构工具等
IMethodSymbol(方法符号):
- 表示方法、构造函数、析构函数、运算符等
- 提供方法签名、参数、返回值、重载信息等
- 用于方法调用分析、参数验证、代码生成等
典型应用场景:
- 生成 DTO 映射代码(需要分析类型的属性)
- 实现依赖注入容器(需要分析构造函数参数)
- 创建序列化器(需要分析类型成员)
- 实现代码分析器(需要检查方法调用)
三种节点类型对比
| 特性 | 语法节点 (Syntax) | 符号 (Symbol) | 语义模型 (SemanticModel) |
|---|---|---|---|
| 表示内容 | 代码的语法结构 | 代码的语义含义 | 连接语法和符号的桥梁 |
| 包含信息 | 标识符、关键字、位置 | 类型、成员、继承关系 | 类型推断、符号查找 |
| 使用场景 | 代码格式化、语法分析 | 类型分析、代码生成 | 获取符号、类型检查 |
| 示例 | ClassDeclarationSyntax | INamedTypeSymbol | GetDeclaredSymbol() |
🚀 快速开始示例
让我们看一个完整的例子,了解如何获取和使用类型和方法符号:
csharp
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
public class QuickStartExample
{
public void AnalyzeTypeAndMethod()
{
// 步骤 1:准备代码
string code = @"
public class UserService
{
public User GetUser(int id)
{
return new User { Id = id };
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
";
// 步骤 2:创建语法树和编译
var syntaxTree = CSharpSyntaxTree.ParseText(code);
var compilation = CSharpCompilation.Create("QuickStart")
.AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location))
.AddSyntaxTrees(syntaxTree);
var semanticModel = compilation.GetSemanticModel(syntaxTree);
var root = syntaxTree.GetRoot();
// 步骤 3:获取类型符号
var userClass = root.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.First(c => c.Identifier.Text == "User");
var userTypeSymbol = semanticModel.GetDeclaredSymbol(userClass) as INamedTypeSymbol;
Console.WriteLine($"类型名称: {userTypeSymbol.Name}");
Console.WriteLine($"类型种类: {userTypeSymbol.TypeKind}");
Console.WriteLine($"是否是引用类型: {userTypeSymbol.IsReferenceType}");
// 步骤 4:获取方法符号
var getUserMethod = root.DescendantNodes()
.OfType<MethodDeclarationSyntax>()
.First(m => m.Identifier.Text == "GetUser");
var methodSymbol = semanticModel.GetDeclaredSymbol(getUserMethod) as IMethodSymbol;
Console.WriteLine($"方法名称: {methodSymbol.Name}");
Console.WriteLine($"返回类型: {methodSymbol.ReturnType.Name}");
Console.WriteLine($"参数数量: {methodSymbol.Parameters.Length}");
}
}提示
使用 GetDeclaredSymbol() 从语法节点获取符号,使用 GetSymbolInfo() 从表达式获取符号。
📊 API 速查表
类型符号常用 API
| API | 说明 | 返回类型 | 示例 | 场景 |
|---|---|---|---|---|
Name | 获取类型名称 | string | typeSymbol.Name | 获取类型名称 |
TypeKind | 获取类型种类 | TypeKind | typeSymbol.TypeKind | 判断是类/接口/结构 |
BaseType | 获取基类 | INamedTypeSymbol | typeSymbol.BaseType | 分析继承关系 |
Interfaces | 获取实现的接口 | ImmutableArray<INamedTypeSymbol> | typeSymbol.Interfaces | 分析接口实现 |
GetMembers() | 获取所有成员 | ImmutableArray<ISymbol> | typeSymbol.GetMembers() | 遍历类型成员 |
IsGenericType | 是否是泛型类型 | bool | typeSymbol.IsGenericType | 检查泛型 |
TypeParameters | 获取类型参数 | ImmutableArray<ITypeParameterSymbol> | typeSymbol.TypeParameters | 分析泛型参数 |
IsReferenceType | 是否是引用类型 | bool | typeSymbol.IsReferenceType | 判断类型类别 |
IsValueType | 是否是值类型 | bool | typeSymbol.IsValueType | 判断类型类别 |
IsRecord | 是否是记录类型 | bool | typeSymbol.IsRecord | 检查记录类型 |
方法符号常用 API
| API | 说明 | 返回类型 | 示例 | 场景 |
|---|---|---|---|---|
Name | 获取方法名称 | string | methodSymbol.Name | 获取方法名称 |
ReturnType | 获取返回类型 | ITypeSymbol | methodSymbol.ReturnType | 分析返回值 |
Parameters | 获取参数列表 | ImmutableArray<IParameterSymbol> | methodSymbol.Parameters | 分析参数 |
IsAsync | 是否是异步方法 | bool | methodSymbol.IsAsync | 检查异步方法 |
IsExtensionMethod | 是否是扩展方法 | bool | methodSymbol.IsExtensionMethod | 检查扩展方法 |
IsGenericMethod | 是否是泛型方法 | bool | methodSymbol.IsGenericMethod | 检查泛型方法 |
MethodKind | 获取方法种类 | MethodKind | methodSymbol.MethodKind | 判断方法类型 |
OverriddenMethod | 获取被重写的方法 | IMethodSymbol | methodSymbol.OverriddenMethod | 分析方法重写 |
IsVirtual | 是否是虚方法 | bool | methodSymbol.IsVirtual | 检查虚方法 |
IsOverride | 是否是重写方法 | bool | methodSymbol.IsOverride | 检查重写 |
🔗 深入学习
本文档提供了类型和方法符号的概览和快速入门。要深入学习,请参阅以下专题文档:
1. 类型系统详解
内容包括:
- INamedTypeSymbol 核心属性详解
- 泛型类型处理(开放泛型、封闭泛型、类型参数)
- 继承和接口(基类访问、接口实现、继承链遍历)
- 特殊类型处理(枚举、委托、记录、元组)
适合场景:
- 需要深入分析类型结构
- 处理复杂的泛型类型
- 分析类型继承关系
- 生成类型相关的代码
2. 方法分析详解
内容包括:
- IMethodSymbol 核心属性详解
- 方法签名分析
- 参数和返回值处理
- 方法重载和重写
- 扩展方法和泛型方法
适合场景:
- 需要分析方法调用
- 处理方法重载和重写
- 分析方法参数
- 生成方法相关的代码
3. 实战示例和最佳实践
文档: semantic-model-type-examples.md
内容包括:
- 完整的类型分析器示例
- 真实使用场景(查找派生类、分析接口实现、生成代码)
- 最佳实践(符号比较、泛型处理、null 检查等)
- 反模式和陷阱(常见错误及解决方案)
- 高级主题和可视化图表
适合场景:
- 学习完整的实战案例
- 了解最佳实践
- 避免常见错误
- 理解复杂的类型关系