You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#运行时利用反射合并集合包装类List<T>属性问题求解

运行时动态合并泛型集合包装类实现

场景说明

当前需要处理封装了List<T>集合的自定义类,示例类结构如下:

public class CollA 
{
  public List<SomeType> Items {get;set;}

  // 其他不相关属性
}

已知约束:所有这类集合包装类有且仅有一个List<T>类型的属性。
需求为:传入多个同类型包装类实例,返回一个全新的同类型实例,其集合属性包含所有传入实例集合属性的元素合集,预期效果如下:

// 注:原示例对象初始化语法存在笔误,已修正
var A = new CollA{ Items = new List<SomeType> 
{
  new SomeType("A"), new SomeType("B")
}};
var B = new CollA{ Items = new List<SomeType> 
{
  new SomeType("C"), new SomeType("D")
}};

var result = SomeMythicalCombine<CollA>(A, B);
// result.Items 按顺序包含:new SomeType("A"), new SomeType("B"), new SomeType("C"), new SomeType("D")

由于类型只有运行时才能确定,无法在编译期写死特定类型的处理逻辑,已通过反射写出部分实现代码:

public T SomeMythicalCombine<T>(params object[] collections)
{
    var collectionType = typeof(T);
    
    var listProperty = collectionType.GetProperties()
        .Single(p=> typeof(IList).IsAssignableFrom(p.PropertyType));

    var listPropertyName = listProperty.Name;

    var result = Activator.CreateInstance(collectionType);

    var innerType = listProperty.PropertyType.GenericTypeArguments[0];
    var listType = typeof(List<>).MakeGenericType(innerType);
    var list = Activator.CreateInstance(listType);
    
    foreach(var collection in collections)
    {
        var listValues = collection.GetType().GetProperty(listPropertyName).GetValue(collection);
        
        // 逻辑缺口:listValues为object类型,需要转为可遍历结构,调用(list as IList).Add()完成元素添加
    }   
    
    result.GetType().GetProperty(listPropertyName).SetValue(result, list);
    
    return result as T;
}

待补全逻辑:PropertyInfo.GetValue()返回的listValues是object类型,需要转为可遍历类型,逐个将元素加入新创建的列表中完成合并。

实现方案

不需要将listValues强转为具体的泛型List<T>类型。所有List<T>都实现了非泛型System.Collections.IEnumerable接口,直接将listValues转为该非泛型接口即可完成遍历;同时新创建的list转为非泛型IList后,Add方法接收object类型参数,无需感知具体泛型类型就可以直接传入遍历到的元素。
补全后的核心代码如下:

// 提前将新列表转为非泛型IList,避免循环内重复转换
IList resultList = list as IList;
foreach(var collection in collections)
{
    // 跳过空入参避免空引用异常
    if (collection == null) continue;
    var listValues = collection.GetType().GetProperty(listPropertyName).GetValue(collection);
    // 跳过集合属性为null的实例
    if (listValues == null) continue;
    // 直接转非泛型IEnumerable遍历,不需要知道具体元素类型
    foreach (var item in listValues as System.Collections.IEnumerable)
    {
        resultList.Add(item);
    }
}

可选优化点

  • 默认的GetProperties()方法仅查找公共实例属性,如果存在非公共属性场景,可以传入绑定标记扩展查找范围:GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
  • 增加入参类型校验,确保传入的所有collections都与泛型T类型一致,避免运行时找不到对应属性抛出异常
  • 如果有去重需求,可以在所有元素添加完成后,通过反射调用对应泛型的Distinct方法处理,纯合集场景直接调用Add即可

内容的提问来源于stack exchange,提问作者Stuart Hemming

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 23:33:20