C#遍历Shipment对象及嵌套属性,实现空值填充需求
解决反射处理嵌套对象与集合的属性填充问题
我完全理解你遇到的痛点——反射处理简单属性还好,但碰到嵌套对象(比如Consignor、Consignee)和集合(比如List<Invoice>)时,逻辑会复杂很多。下面我会给你一套完整的解决方案,一步步处理不同类型的属性:
1. 核心思路
我们需要编写一个通用的反射工具方法,它能:
- 遍历对象的所有公共属性
- 对简单值类型/字符串:判断源对象(Shipment1)属性是否为null或空,是则用目标对象(Shipment2)的对应值覆盖
- 对嵌套引用对象(比如Consignor):递归调用填充方法,因为这些对象本身也有需要检查的属性
- 对集合类型(比如List
):需要先判断源集合是否为null或空,再处理集合中的每个元素(或者直接替换集合,根据你的需求)
2. 完整代码实现
首先假设你的嵌套类结构大概是这样(你可以根据实际情况调整):
public class Consignor { public string Name { get; set; } public string Address { get; set; } // 其他属性... } public class Consignee { public string Name { get; set; } public string Contact { get; set; } // 其他属性... } public class Invoice { public int InvoiceId { get; set; } public decimal Amount { get; set; } // 其他属性... }
然后编写通用的填充方法:
using System; using System.Collections; using System.Collections.Generic; using System.Reflection; public static class ObjectMergeHelper { public static void MergeNullProperties<T>(T source, T target) where T : class { if (source == null || target == null) throw new ArgumentNullException("Source or target object cannot be null"); Type type = typeof(T); foreach (PropertyInfo property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { // 获取源对象的属性值 object sourceValue = property.GetValue(source); // 获取目标对象的属性值 object targetValue = property.GetValue(target); // 跳过只读属性 if (!property.CanWrite) continue; // 处理不同类型的属性 if (IsSimpleType(property.PropertyType)) { // 简单类型:检查是否为null或空值(字符串单独判断空) bool isSourceEmpty = IsNullOrEmptyValue(sourceValue); if (isSourceEmpty && targetValue != null) { property.SetValue(source, targetValue); } } else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && property.PropertyType != typeof(string)) { // 处理集合类型(排除字符串) MergeCollections(sourceValue, targetValue, property, source); } else if (property.PropertyType.IsClass) { // 嵌套引用对象:递归调用合并方法 if (sourceValue == null && targetValue != null) { // 如果源对象的嵌套属性是null,直接创建一个新实例并复制目标值 object newInstance = Activator.CreateInstance(property.PropertyType); MergeNullProperties(newInstance, targetValue); property.SetValue(source, newInstance); } else if (sourceValue != null && targetValue != null) { // 如果源对象的嵌套属性已存在,递归合并其内部属性 MergeNullProperties(sourceValue, targetValue); } } } } // 判断是否为简单类型(值类型+字符串) private static bool IsSimpleType(Type type) { return type.IsValueType || type == typeof(string); } // 判断值是否为null或空(字符串判断Empty) private static bool IsNullOrEmptyValue(object value) { if (value == null) return true; if (value is string str) return string.IsNullOrEmpty(str); return false; } // 处理集合的合并逻辑 private static void MergeCollections(object sourceCollection, object targetCollection, PropertyInfo property, object sourceObj) { // 如果源集合是null或空,且目标集合有内容,直接替换源集合 if ((sourceCollection == null || !((IEnumerable)sourceCollection).GetEnumerator().MoveNext()) && targetCollection != null) { // 这里可以选择直接复制集合,或者逐个元素合并,根据你的需求 // 示例:直接创建一个新的同类型集合并复制元素 Type genericType = property.PropertyType.GetGenericArguments()[0]; Type listType = typeof(List<>).MakeGenericType(genericType); IList newCollection = (IList)Activator.CreateInstance(listType); foreach (var item in (IEnumerable)targetCollection) { // 如果是引用类型,需要创建副本避免引用共享;值类型直接添加 if (genericType.IsClass && genericType != typeof(string)) { object itemCopy = Activator.CreateInstance(genericType); MergeNullProperties(itemCopy, item); newCollection.Add(itemCopy); } else { newCollection.Add(item); } } property.SetValue(sourceObj, newCollection); } else if (sourceCollection != null && targetCollection != null) { // 如果源集合已有内容,你可以选择合并元素(比如根据ID匹配),或者跳过 // 这里示例是跳过,如果你需要更复杂的集合合并,可以扩展逻辑 // 比如:遍历目标集合,将源集合中不存在的元素添加进去,或者更新匹配的元素 } } }
3. 使用方法
在你的业务代码中,直接调用这个工具方法即可:
// 假设你已经有了Shipment1和Shipment2实例 Shipment shipment1 = new Shipment(); // shipment1的部分属性为null或空... Shipment shipment2 = new Shipment(); // shipment2有完整的属性值... // 执行合并:将shipment2的非空属性填充到shipment1的空属性中 ObjectMergeHelper.MergeNullProperties(shipment1, shipment2);
4. 关键细节说明
- 递归处理嵌套对象:对于
Consignor、Consignee这类嵌套类,我们递归调用MergeNullProperties,确保它们的内部属性也会被检查和填充 - 集合处理逻辑:示例中是当源集合为空时,直接复制目标集合的元素(并创建副本避免引用共享),你可以根据实际需求调整——比如如果需要合并集合中已有的元素(比如根据
InvoiceId匹配更新),可以修改MergeCollections方法 - 简单类型判断:区分简单类型和复杂类型,避免对嵌套对象做简单的null判断
- 空值判断:单独处理字符串的
NullOrEmpty,其他值类型只判断null(不过值类型本身不能为null,除非是可空值类型,代码中也能处理)
这个方案应该能解决你遇到的嵌套对象和集合的反射处理问题,你可以根据自己的类结构和业务需求再调整细节~
内容的提问来源于stack exchange,提问作者RimKaMz
相关产品推荐
相关产品推荐

