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

如何正确检测C#类的可空属性类型?现有方法结果不符

问题:C# 反射检测可空类型不符合预期

我用反射检测Candidate类的属性是否可空,当前代码仅识别DateOfBirth为可空类型,但预期MiddleName、DateOfBirth、Gender都应该被判定为可空。最终目的是确定FirstName和LastName在数据库保存时不可为空。

现有代码

Candidate类(脚手架生成)

public partial class Candidate
{
    public int Id { get; set; }
    public string FirstName { get; set; } = null!;
    public string? MiddleName { get; set; }
    public string LastName { get; set; } = null!;
    public DateTime? DateOfBirth { get; set; }
    public string? Gender { get; set; }
}

检测方法

public static bool CheckPro()
{
    System.Reflection.PropertyInfo[] properties = typeof(Candidate).GetProperties();
    System.Reflection.PropertyInfo[] readableProperties = properties.Where(w => w.CanRead).ToArray();
    foreach (var property in readableProperties)
    {
        var propertyType = property.PropertyType;          
        if (System.Nullable.GetUnderlyingType(propertyType) != null)
        {
            Debug.WriteLine(property.Name + " -> 可空类型 ");
        }
        else
        {
            Debug.WriteLine(property.Name + " -> 不可空类型 ");
        }
    }
    return false;
}

当前输出

Id -> 不可空类型 
FirstName -> 不可空类型 
MiddleName -> 不可空类型 
LastName -> 不可空类型 
DateOfBirth -> 可空类型 
Gender -> 不可空类型 

问题原因

System.Nullable.GetUnderlyingType只能识别值类型的可空包装(比如DateTime?本质是Nullable<DateTime>结构体),而string?是C# 8.0引入的可为空引用类型,这是编译时的语法注解,反射时property.PropertyType仍然是string,不会被Nullable.GetUnderlyingType识别。

解决方案

要同时支持检测值类型可空和可为空引用类型,需要:

  1. 先检查是否是值类型可空(用Nullable.GetUnderlyingType)
  2. 对于引用类型,检查属性是否带有NullableAttribute,并判断其参数是否表示可空

修改后的检测方法:

using System.Reflection;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

public static bool CheckPro()
{
    PropertyInfo[] readableProperties = typeof(Candidate).GetProperties()
        .Where(w => w.CanRead)
        .ToArray();
        
    foreach (var property in readableProperties)
    {
        var propertyType = property.PropertyType;
        bool isNullable = false;
        
        // 检查值类型可空(Nullable<T>)
        if (Nullable.GetUnderlyingType(propertyType) != null)
        {
            isNullable = true;
        }
        // 检查引用类型的可为空注解
        else if (!propertyType.IsValueType)
        {
            var nullableAttr = property.GetCustomAttribute<NullableAttribute>();
            if (nullableAttr != null)
            {
                // NullableAttribute的参数表示可空状态,0 = 可空,1 = 不可空
                isNullable = nullableAttr.NullableFlags[0] == 0;
            }
            // 检查NotNullAttribute(对应null!注解)
            var notNullAttr = property.GetCustomAttribute<NotNullAttribute>();
            if (notNullAttr != null)
            {
                isNullable = false;
            }
        }
        
        Debug.WriteLine($"{property.Name} -> {(isNullable ? "可空类型" : "不可空类型")}");
    }
    return false;
}

修改后预期输出

Id -> 不可空类型 
FirstName -> 不可空类型 
MiddleName -> 可空类型 
LastName -> 不可空类型 
DateOfBirth -> 可空类型 
Gender -> 可空类型 

补充说明

如果是EF Core脚手架生成的实体类,还可以通过检查RequiredAttribute直接判断数据库是否允许为空:

var isDbRequired = property.GetCustomAttribute<System.ComponentModel.DataAnnotations.RequiredAttribute>() != null;

内容的提问来源于stack exchange,提问作者Unis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 06:09:11