如何合并实现List接口的泛型ApiResult<T>实例?
问题描述
我有一组DTO及容器DTO,例如BankDetails和继承自List<BankDetails>的容器DTOListOfBankDetails。我有一个泛型网络方法,它可能返回多个容器DTO的ApiResult<T>,需要将它们合并为一个ApiResult<T>(但T并非始终为列表类型)。ApiResult类的MergeResult成员用于合并另一个ApiResult<T>,此时T为DTO集合(如ListOfBankDetails)。
当前实现的MergeResult方法如下:
public class ApiResult<T> { public T Response { get; set; } public void MergeResult(ApiResult<T> toMerge) { if (Response != null && toMerge.Response != null) { (Response as List<object>).AddRange(toMerge.Response as List<object>); } } }
但将Response转为List<object>会返回null;我也尝试了以下实现,但Concat操作后转换为T类型失败:
public void MergeResult(ApiResult<T> toMerge) { if (Response != null && toMerge.Response != null) { Response = (T)((Response as IEnumerable<object>).Concat(toMerge.Response as IEnumerable<object>)); } }
请问如何合并两个实现List接口的泛型类型?
解决方案
方法一:利用非泛型IList接口直接添加元素
所有List<T>及其子类都实现了非泛型的IList接口,借助这个接口可以直接遍历并添加元素,避开泛型转换的问题:
public class ApiResult<T> { public T Response { get; set; } public void MergeResult(ApiResult<T> toMerge) { if (Response == null || toMerge.Response == null) return; // 将Response转换为非泛型IList var currentCollection = Response as System.Collections.IList; var mergeCollection = toMerge.Response as System.Collections.IList; if (currentCollection != null && mergeCollection != null) { foreach (var item in mergeCollection) { currentCollection.Add(item); } } } }
这个方案代码简洁,性能优于反射,兼容所有继承自List<T>的容器DTO,同时对非集合类型的T能自动跳过合并逻辑。
方法二:反射调用AddRange方法(兼容更多集合类型)
如果容器DTO可能实现了ICollection<T>但不是List<T>的子类,可以用反射动态获取并调用AddRange方法:
public class ApiResult<T> { public T Response { get; set; } public void MergeResult(ApiResult<T> toMerge) { if (Response == null || toMerge.Response == null) return; // 获取当前T实现的ICollection<TItem>接口 var collectionInterface = typeof(T).GetInterface(typeof(ICollection<>).FullName); if (collectionInterface == null) return; // 获取集合的元素类型 var itemType = collectionInterface.GetGenericArguments()[0]; // 获取AddRange方法(List<T>及部分集合类型实现了该方法) var addRangeMethod = typeof(T).GetMethod("AddRange", new[] { typeof(IEnumerable<>).MakeGenericType(itemType) }); if (addRangeMethod != null) { addRangeMethod.Invoke(Response, new[] { toMerge.Response }); } } }
这个方案兼容性更强,只要目标集合类型带有AddRange方法就能工作,但反射会带来轻微的性能开销。
原实现失败原因
- 第一种实现中,
List<BankDetails>无法直接转换为List<object>:泛型List<T>不支持协变,即使BankDetails是引用类型,也不能向上转换为List<object>,所以转换结果为null。 - 第二种实现中,
Concat返回的是IEnumerable<object>,它不是T(比如ListOfBankDetails)的实例,强制类型转换必然失败,因为IEnumerable无法直接转为具体的集合类型。
内容的提问来源于stack exchange,提问作者Moffen
相关产品推荐
相关产品推荐

