如何正确检测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识别。
解决方案
要同时支持检测值类型可空和可为空引用类型,需要:
- 先检查是否是值类型可空(用
Nullable.GetUnderlyingType) - 对于引用类型,检查属性是否带有
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
相关产品推荐
相关产品推荐

