基于Roslyn获取当前项目C#语言版本,优化空参数校验重构
我最近在用Roslyn开发一个自动添加ArgumentNullException的简单重构工具,正好碰到了需要根据项目C#版本适配不同写法的问题,这里把思路和解决方法整理出来:
需求背景
这个工具的核心功能是自动为方法参数生成null检查代码,但不同C#版本的最优写法差异很大:
- C# 6之前:只能用硬编码字符串传递参数名,可读性和安全性都一般:
if (parameter == null) throw new ArgumentNullException("parameter"); _parameter = parameter;
- C# 6+:可以用
nameof运算符,既保留可读性又实现类型安全:
if (parameter == null) throw new ArgumentNullException(nameof(parameter)); _parameter = parameter;
- C# 7+:借助throw表达式能把代码简化成一行,更加简洁:
_parameter = parameter ?? throw new ArgumentNullException(nameof(parameter));
要让工具自动适配这些写法,关键就是通过Roslyn获取当前项目的C#语言版本。
获取C#版本的具体实现
在Roslyn的分析器或代码修复提供者中,我们可以通过Compilation对象轻松拿到版本信息:
- 首先从分析上下文(比如
SyntaxNodeAnalysisContext)或代码修复上下文(CodeFixContext)中获取Compilation实例; - 访问
Compilation.LanguageVersion属性,它会返回一个LanguageVersion枚举值,对应项目的C#版本。
举个实际的代码示例:
public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeAction(AnalyzeParameterAssignment, SyntaxKind.AssignmentExpression); } private void AnalyzeParameterAssignment(SyntaxNodeAnalysisContext context) { // 获取当前项目的编译信息 var compilation = context.Compilation; var csharpVersion = compilation.LanguageVersion; // 根据版本选择对应的代码生成逻辑 if (csharpVersion >= LanguageVersion.CSharp7) { // 生成C#7+的throw表达式写法 GenerateThrowExpressionNullCheck(context); } else if (csharpVersion >= LanguageVersion.CSharp6) { // 生成C#6+带nameof的写法 GenerateNameofNullCheck(context); } else { // 生成传统硬编码字符串的写法 GenerateLegacyNullCheck(context); } }
额外注意点
LanguageVersion枚举覆盖了从C# 1到最新正式/预览版本的所有取值,比如CSharp8、CSharp10、Preview等,能满足绝大多数场景的判断;- 如果项目设置了
latest版本,LanguageVersion会自动映射到当前Roslyn支持的最新正式版本,无需额外处理。
内容的提问来源于stack exchange,提问作者Akos Nagy
相关产品推荐
相关产品推荐

