You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 23:06:09