基于Roslyn Analyzer检查只读字段的MessageKey唯一性
问题描述
项目内存在数百个分散在多类、多项目中的错误码定义,形式如下:
public readonly ErrorMessageCode 00001 = new ErrorMessageCode() { MessageKey = "00001", Title = "Error!", Message = "You did something wrong!" };
由于MessageKey是数据库主键,要求全局唯一,希望通过自定义Roslyn Analyzer Rule实现重复MessageKey的自动检查,目前已有自定义规则的依赖基础,但从未编写过此类跨项目的唯一性检查规则。
实现方案
完全可以实现这类全局唯一性检查,核心思路是通过Roslyn分析整个解决方案的语义模型,收集所有MessageKey值并比对重复,具体步骤如下:
1. 识别目标字段与初始化器
在Analyzer中注册语法分析器,定位所有符合以下特征的代码节点:
- 字段修饰符包含
public readonly - 字段类型为
ErrorMessageCode - 字段初始化使用对象初始化器(
new ErrorMessageCode() { ... })
2. 提取MessageKey属性值
遍历对象初始化器中的所有属性赋值节点,筛选出MessageKey对应的赋值语句,提取其字符串字面量的值。核心逻辑示例:
// 假设node是对象初始化器节点(ObjectCreationExpressionSyntax) var initializer = node.Initializer; foreach (var assignment in initializer.Expressions.OfType<AssignmentExpressionSyntax>()) { if (assignment.Left is IdentifierNameSyntax identifier && identifier.Identifier.Text == "MessageKey") { if (assignment.Right is LiteralExpressionSyntax literal) { var messageKey = literal.Token.ValueText; // 收集messageKey用于后续检查 } } }
3. 跨项目收集与去重检查
由于错误码分散在多个项目,需要启用解决方案级分析:
- 使用Roslyn的
IncrementalGenerator或注册支持解决方案级的Analyzer,确保能遍历所有项目的编译单元 - 维护一个全局
HashSet<string>存储已收集的MessageKey,每处理一个字段时:- 若当前
MessageKey已存在,在对应的赋值位置报告重复错误诊断 - 若不存在,将其加入集合
- 若当前
4. 复用现有自定义规则基础
如果已有自定义规则的依赖类,可直接复用:
- 复用已有的
DiagnosticDescriptor定义(指定错误ID、标题、描述等) - 复用规则注册逻辑,将新分析器添加到规则集中
关键注意事项
- 确保Analyzer能访问到
ErrorMessageCode类型的语义信息,避免因项目引用问题导致无法识别类型 - 对于非字符串字面量的动态
MessageKey赋值,可添加诊断提示,要求必须使用固定字面量,保证检查有效性 - 测试时需覆盖跨项目的重复场景,验证解决方案级分析的正确性
内容的提问来源于stack exchange,提问作者RedSonja
相关产品推荐
相关产品推荐

