如何通过反射判断可空集合属性、校验有值并获取其数据类型
可空集合类型反射处理实现方案
原代码存在的核心问题
遍历逻辑中混淆了属性的类型元数据和属性的运行时实例值,直接对拿到的属性值调用类型判断、数据类型获取的扩展方法:
- 当属性值为null时,无法从实例反向获取对应的类型定义,所有类型匹配判断都会失效
- 扩展方法的挂载对象错误,导致可空集合、有效值的判断逻辑完全无法触发
最终所有可空集合属性都无法被正确识别。
核心实现逻辑
三个需求的实现完全基于反射的元数据规则完成,不需要对现有SomeClass的定义做任何修改:
- 可空集合类型判断:基于
IEnumerable类型约束识别集合,再校验集合的元素类型是否为Nullable<T>形式 - 有效值判断:先校验集合实例是否为null,再遍历集合元素,只要存在任意非null的元素即判定为包含有效值
- 关联数据类型获取:从集合的可空元素类型中提取
Nullable<T>对应的基础值类型
可复用的扩展方法代码
/// <summary> /// 判断类型是否为「元素为可空值类型的集合」 /// </summary> public static bool IsNullableCollection(this Type type) { // 跳过非集合类型 if (!typeof(IEnumerable).IsAssignableFrom(type)) return false; Type elementType; // 处理数组类型的集合 if (type.IsArray) { elementType = type.GetElementType(); } // 处理泛型集合(如List<T>) else if (type.IsGenericType) { elementType = type.GetGenericArguments()[0]; } // 跳过非泛型、非数组的集合类型 else { return false; } // 校验元素类型是否为可空值类型 return elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof(Nullable<>); } /// <summary> /// 判断可空集合是否包含非空有效值 /// </summary> public static bool HasValidValue(this IEnumerable collection) { if (collection == null) return false; foreach (var item in collection) { if (item != null) return true; } return false; } /// <summary> /// 获取可空集合的基础数据类型 /// </summary> public static Type GetCollectionUnderlyingType(this Type nullableCollectionType) { Type elementType; if (nullableCollectionType.IsArray) { elementType = nullableCollectionType.GetElementType(); } else { elementType = nullableCollectionType.GetGenericArguments()[0]; } return Nullable.GetUnderlyingType(elementType); }
修正后的属性探查逻辑
public class SomeOtherClass { public string Discover(SomeClass someClass) { var sb = new StringBuilder(); foreach (var propertyInfo in someClass.GetType().GetProperties()) { // 先基于属性元数据判断是否为可空集合 if (!propertyInfo.PropertyType.IsNullableCollection()) continue; // 获取属性的实际运行时值 var propCollection = propertyInfo.GetValue(someClass) as IEnumerable; // 判断集合是否包含有效值 if (!propCollection.HasValidValue()) continue; // 获取集合对应的基础数据类型 var underlyingType = propertyInfo.PropertyType.GetCollectionUnderlyingType(); // 按预期格式拼接输出 sb.AppendLine($"{propertyInfo.Name} has values and data type is {underlyingType.Name.ToLower()}"); } return sb.ToString().TrimEnd(); } }
测试验证结果
按照给定的测试场景(仅为PropertyX赋值为包含两个有效数值的int?[2]数组,其他属性均为默认null值),最终输出内容为:
PropertyX has values and data type is int
所有未赋值的可空集合属性、普通字符串属性都会被自动过滤,不会出现在结果中。
内容的提问来源于stack exchange,提问作者rlyonsii
相关产品推荐
相关产品推荐

