如何在Nullable<T>字段默认值为null时获取其底层类型?
我太懂你这种遇到XML解析卡壳的烦躁了!用可空类型存可选属性本来是顺理成章的事,结果碰到字段默认是null的时候,想拿类型信息直接调用.GetType()要么报错要么拿不到正确结果,简直让人挠头对吧?
其实核心问题在于:当Nullable<T>类型的字段值为null时,它本质上是没有实例的(毕竟Nullable<T>是值类型的包装),直接对null调用.GetType()会抛出NullReferenceException,而且也没法从值本身拿到类型信息。这时候你得换个思路——从字段的声明类型入手,而不是从当前的实例值。
给你几种实用的解决方法:
1. 编译时已知字段类型的情况
如果是直接针对某个类的特定字段,你可以用typeof操作符拿到字段的声明类型,再结合Nullable.GetUnderlyingType方法提取底层类型,完全不受当前字段值是否为null的影响:
比如你的类是这样的:
public class XmlParsedClass { public int? Age { get; set; } // 默认null public DateTime? RegisterDate { get; set; } // 默认null }
要拿Age字段的底层类型,直接这么写:
// 针对字段的声明类型获取 Type nullableType = typeof(XmlParsedClass.Age); Type underlyingType = Nullable.GetUnderlyingType(nullableType); // 这里underlyingType就是int的Type,不管Age当前是不是null
2. 运行时反射遍历类成员的情况
如果是解析XML时需要反射遍历类的所有字段/属性(比如通用解析逻辑),同样用Nullable.GetUnderlyingType处理成员的声明类型就行:
举个完整的示例代码:
var xmlObj = new XmlParsedClass(); // 所有可空字段默认都是null // 遍历类的所有属性 foreach (var prop in typeof(XmlParsedClass).GetProperties()) { Type propDeclaredType = prop.PropertyType; // 尝试获取可空类型的底层类型 Type? underlyingType = Nullable.GetUnderlyingType(propDeclaredType); if (underlyingType != null) { Console.WriteLine($"属性「{prop.Name}」是可空值类型,底层类型:{underlyingType.Name}"); } else { // 要么是非可空值类型,要么是可空引用类型(比如string?) Console.WriteLine($"属性「{prop.Name}」的类型:{propDeclaredType.Name}"); } }
这里要注意区分:int?、DateTime?这种是可空值类型(本质是Nullable<T>结构),而string?是可空引用类型(只是C# 8.0+的编译器注解,实际类型还是string),Nullable.GetUnderlyingType只会对可空值类型返回底层的T,对其他类型返回null,刚好符合你解析XML时的类型判断需求。
3. 拿到装箱后的null对象的情况
如果你的变量是object类型,且值为null(比如从字段值装箱而来),这时候从值本身是拿不到任何类型信息的——因为装箱后的null没有类型标识。这种情况你必须回到字段/属性的声明类型去获取,也就是上面两种方法的思路,不能从null值本身入手。
回到你解析XML的场景,正确的流程应该是:先通过反射拿到类成员的声明类型,提取出底层类型(如果是可空值类型),再根据XML中是否存在该属性来决定是转换值还是设为null,完全不需要依赖字段当前的实例值来拿类型。
备注:内容来源于stack exchange,提问作者Planeptunia

