如何在C#源代码生成器中检测可空枚举类型?
解决方案
要检测可空枚举(以及int?这类可空值类型),需要先获取类型的底层非可空值类型,再判断该底层类型是否为枚举。Roslyn中可空值类型有两种表现形式:显式的Nullable<T>泛型,以及C# 8+空值上下文里的T?语法(带NullableAnnotation.Annotated标记的值类型),需要同时处理这两种情况。
步骤1:获取Nullable<>的符号引用
首先从编译上下文获取Nullable<>泛型类型的符号,用于后续对比判断:
var nullableGenericType = compilation.GetTypeSymbol(typeof(Nullable<>)) as INamedTypeSymbol;
步骤2:提取可空值类型的底层类型
编写逻辑处理两种可空值类型的情况,提取出底层的非可空值类型:
var propertyType = classProperty.Type; INamedTypeSymbol? underlyingValueType = null; // 处理显式的Nullable<T>泛型(如Nullable<MyEnum>) if (propertyType is INamedTypeSymbol namedType && namedType.IsGenericType) { if (SymbolEqualityComparer.Default.Equals(namedType.ConstructedFrom, nullableGenericType)) { underlyingValueType = namedType.TypeArguments[0] as INamedTypeSymbol; } } // 处理C# 8+的T?语法(如MyEnum?,仅在空值启用上下文生效) else if (propertyType.NullableAnnotation == NullableAnnotation.Annotated && propertyType.IsValueType) { underlyingValueType = propertyType as INamedTypeSymbol; }
步骤3:判断底层类型是否为枚举
用你已有的非空枚举检测逻辑,判断提取出的底层类型:
bool isNullableEnum = underlyingValueType != null && underlyingValueType.EnumUnderlyingType != null;
完整示例代码
// 在你的源代码生成器逻辑中 var nullableGenericType = compilation.GetTypeSymbol(typeof(Nullable<>)) as INamedTypeSymbol; var propertyType = classProperty.Type; INamedTypeSymbol? underlyingValueType = null; // 检测可空值类型的底层类型 if (propertyType is INamedTypeSymbol namedType && namedType.IsGenericType) { if (SymbolEqualityComparer.Default.Equals(namedType.ConstructedFrom, nullableGenericType)) { underlyingValueType = namedType.TypeArguments[0] as INamedTypeSymbol; } } else if (propertyType.NullableAnnotation == NullableAnnotation.Annotated && propertyType.IsValueType) { underlyingValueType = propertyType as INamedTypeSymbol; } // 判断是否为可空枚举 bool isNullableEnum = underlyingValueType != null && underlyingValueType.EnumUnderlyingType != null; // 额外:判断是否为任意可空值类型(如int?、bool?等) bool isNullableValueType = underlyingValueType != null;
关键说明
- 必须使用
SymbolEqualityComparer.Default对比符号,不能直接用==,Roslyn中符号相等需要通过专用比较器判断。 - 区分可空值类型和可空引用类型:仅当
propertyType.IsValueType为true时,NullableAnnotation.Annotated才表示可空值类型;引用类型的Annotated标记是可空引用类型,不属于Nullable<T>范畴。
内容的提问来源于stack exchange,提问作者ygoe
相关产品推荐
相关产品推荐

