name: 可为空引用类型审计 description: 分析可为空引用类型采用情况,包括警告细分和迁移建议 argument-hint: “[–project <name>] [–detailed] [–warnings]” allowed-tools: Bash, Read, Glob, Grep, AskUserQuestion
/dotnet:可为空引用类型审计
分析代码库中可为空引用类型(NRT)的采用情况,提供详细警告细分和迁移建议。
参数
从 $ARGUMENTS 解析参数:
| 标志 | 描述 | 默认值 |
|---|---|---|
--project <path> |
目标特定项目(模糊匹配) | 所有项目 |
--detailed |
显示按文件细分 | false |
--warnings |
显示所有可为空警告 | false |
工作流程
第1步:扫描项目配置
检查项目文件中的可为空状态:
# 查找所有项目文件
find . -name "*.csproj" -type f
# 检查是否为可为空启用
grep -l "<Nullable>enable</Nullable>" **/*.csproj
grep -l "<Nullable>disable</Nullable>" **/*.csproj
grep -l "<Nullable>warnings</Nullable>" **/*.csproj
grep -l "<Nullable>annotations</Nullable>" **/*.csproj
检查 Directory.Build.props 以获取解决方案范围内的设置。
第2步:扫描源文件
对于没有解决方案范围内可为空的项目:
# 查找带有 #nullable 指令的文件
grep -r "#nullable enable" --include="*.cs" .
grep -r "#nullable disable" --include="*.cs" .
grep -r "#nullable restore" --include="*.cs" .
统计总 .cs 文件与可为空启用文件的比率。
第3步:收集可为空警告
构建并捕获可为空警告:
dotnet build 2>&1 | grep -E "CS86[0-9]{2}|CS87[0-9]{2}"
按警告类型分类:
- CS8600:转换 null 字面量
- CS8601:可能的空引用赋值
- CS8602:解除引用可能为空引用
- CS8603:可能的空引用返回
- CS8604:可能的空引用参数
- CS8618:非空字段未初始化
- CS8625:无法将 null 转换为非空
- CS8765:参数的可空性不匹配
第4步:生成报告
输出格式
摘要报告:
可为空引用类型审计
解决方案:MyApp.sln
项目数:12
┌─────────────────────────────────────────────────────────────┐
│ 可为空采用状态 │
├─────────────────────────────────────────────────────────────┤
│ 项目 状态 文件 问题数 │
├─────────────────────────────────────────────────────────────┤
│ src/MyApp.Core 启用 45 12 │
│ src/MyApp.Api 启用 32 8 │
│ src/MyApp.Infrastructure 启用 28 23 │
│ src/MyApp.Domain 启用 18 0 │
│ tests/MyApp.Tests 禁用 42 N/A │
│ src/MyApp.Legacy (未设置) 15 N/A │
└─────────────────────────────────────────────────────────────┘
采用率:83% (10/12 个项目启用可为空)
带有 NRT 的文件:123/180 (68%)
警告摘要:
CS8602 (空解除引用): 18
CS8618 (未初始化字段): 12
CS8604 (空参数): 8
CS8600 (空赋值): 5
总可为空警告: 43
详细报告 (–detailed):
可为空引用类型审计 (详细)
═══════════════════════════════════════════════════════════════
项目:src/MyApp.Infrastructure
可为空:启用 (项目级别)
═══════════════════════════════════════════════════════════════
带有警告的文件:
src/MyApp.Infrastructure/Repositories/UserRepository.cs
- CS8602:第 42 行 - _context.Users 可能为空
- CS8602:第 67 行 - user.Email 可能为空
- CS8618:第 12 行 - _context 未初始化
src/MyApp.Infrastructure/Services/CacheService.cs
- CS8604:第 28 行 - 参数可能为空
- CS8600:第 35 行 - null 赋值
... (更多文件)
无警告的文件 (干净):
src/MyApp.Infrastructure/Extensions/ServiceCollectionExtensions.cs
src/MyApp.Infrastructure/DependencyInjection.cs
... (15 个更多)
───────────────────────────────────────────────────────────────
项目:src/MyApp.Legacy
可为空:未启用
───────────────────────────────────────────────────────────────
此项目未启用可为空引用类型。
要启用,请添加到 .csproj:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
或使用 #nullable enable 指令按文件启用。
警告报告 (–warnings):
按类别分类的可为空警告
CS8602:解除引用可能为空引用 (18 个警告)
────────────────────────────────────────────────────────────────
src/MyApp.Infrastructure/Repositories/UserRepository.cs:42
var name = user.Name.ToUpper(); // user.Name 可能为空
src/MyApp.Api/Controllers/UsersController.cs:67
return Ok(result.Data.Items); // result.Data 可能为空
... (16 个更多)
修复:添加空检查或使用空条件运算符 (?.)
示例:var name = user.Name?.ToUpper() ?? string.Empty;
CS8618:非空字段必须初始化 (12 个警告)
────────────────────────────────────────────────────────────────
src/MyApp.Core/Models/User.cs:12
public string Email { get; set; } // 未初始化
src/MyApp.Core/Models/Order.cs:8
public Customer Customer { get; set; } // 未初始化
... (10 个更多)
修复选项:
1. 用默认值初始化:public string Email { get; set; } = string.Empty;
2. 设为可为空:public string? Email { get; set; }
3. 使用 required 修饰符 (C# 11+):public required string Email { get; set; }
4. 在构造函数中初始化
CS8604:可能的空引用参数 (8 个警告)
────────────────────────────────────────────────────────────────
... (详情)
迁移建议
基于审计结果,提供建议:
迁移建议
1. 立即执行 (高影响,低难度)
─────────────────────────────────────
- 在 src/MyApp.Legacy 中启用可为空 (15 个文件,预计 ~20 个警告)
- 在测试项目中启用可为空 (可选但推荐)
2. 快速解决 (可自动修复)
─────────────────────────────────────
- CS8618 警告:添加 = null! 或 required 修饰符 (12 个警告)
- CS8625 警告:修复 null 字面量赋值 (5 个警告)
运行:/dotnet:fix-warnings --category nullable
3. 需审核 (上下文依赖)
─────────────────────────────────────
- CS8602 解除引用警告:添加空检查 (18 个警告)
- CS8604 参数警告:验证输入 (8 个警告)
这些需要理解 null 是否有效。
4. 可选清理
─────────────────────────────────────
- 移除启用项目中的 #nullable disable 指令 (3 个文件)
- 考虑在测试项目中启用可为空
估计工作量:2-4 小时完成完整迁移
可为空状态参考
| 设置 | 注解 | 警告 |
|---|---|---|
enable |
是 | 是 |
disable |
否 | 否 |
warnings |
否 | 是 |
annotations |
是 | 否 |
示例
# 基本审计摘要
/dotnet:可为空引用类型审计
# 详细按文件细分
/dotnet:可为空引用类型审计 --detailed
# 显示所有可为空警告及修复
/dotnet:可为空引用类型审计 --warnings
# 审计特定项目
/dotnet:可为空引用类型审计 --project MyApp.Core
与其他命令集成
审计后,使用以下命令处理发现:
# 自动修复可能的警告
/dotnet:fix-warnings --category nullable
# 在项目中启用可为空 (手动编辑或使用 Edit 工具)
# 将 <Nullable>enable</Nullable> 添加到 .csproj
# 重新构建以查看剩余警告
/dotnet:build