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

如何实现通用类数据查询函数?解决对象转类与列表数据提取问题

通用列表属性提取函数实现方案

没问题,我来帮你搞定这个通用属性提取的需求!核心思路是用反射来在运行时动态获取类型信息和属性值——毕竟咱们没法提前知道传入的列表具体类型,反射刚好能解决这种“运行时才明确类型”的场景。

实现思路拆解

  1. 先验证传入的对象确实是可枚举类型(比如List<T>都实现了IEnumerable接口,这样才能遍历元素)
  2. 从传入的Type参数中提取列表的元素类型(比如typeof(List<ABC>)对应的元素类型是ABC)
  3. 通过反射获取目标属性的元信息,确保属性存在且可访问
  4. 遍历列表中的每个元素,动态提取指定属性的值并收集结果

完整非泛型实现代码

public List<object> GetData(object obj, Type objType, string propertyName)
{
    var result = new List<object>();

    // 验证传入对象是否为可枚举类型(List<T>等列表类都实现IEnumerable)
    if (!(obj is IEnumerable enumerable))
    {
        throw new ArgumentException("传入的对象必须是可枚举类型(如List<T>)", nameof(obj));
    }

    // 提取列表的元素类型(从List<T>的泛型参数中获取)
    Type elementType = objType.IsGenericType && objType.GetGenericTypeDefinition() == typeof(List<>)
        ? objType.GetGenericArguments()[0]
        : throw new ArgumentException("objType必须是List<T>类型", nameof(objType));

    // 获取目标属性的元信息,确保是公共实例属性
    PropertyInfo property = elementType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
    if (property == null)
    {
        throw new ArgumentException($"类型 {elementType.Name} 中不存在名为 {propertyName} 的公共实例属性", nameof(propertyName));
    }

    // 遍历列表元素,提取属性值
    foreach (var item in enumerable)
    {
        if (item == null)
        {
            result.Add(null);
            continue;
        }
        // 校验元素类型是否匹配,避免类型不一致的异常
        if (!elementType.IsAssignableFrom(item.GetType()))
        {
            throw new InvalidCastException($"列表中的元素类型 {item.GetType().Name} 与指定的 {elementType.Name} 不匹配");
        }
        object value = property.GetValue(item);
        result.Add(value);
    }

    return result;
}

调用示例

用你提供的ABC类来测试:

// 初始化测试数据
var listABC = new List<ABC>
{
    new ABC { A1 = 10, B1 = true, C1 = "First" },
    new ABC { A1 = 20, B1 = false, C1 = "Second" }
};

// 提取所有A1属性的值
var a1Values = GetData(listABC, typeof(List<ABC>), "A1");
foreach (var val in a1Values)
{
    Console.WriteLine(val); // 输出:10、20
}

优化方案:泛型版本(更类型安全)

如果调用方可以明确类型,泛型版本会更安全,还能避免object装箱的开销:

public List<TProperty> GetGenericData<T, TProperty>(List<T> list, string propertyName)
{
    var result = new List<TProperty>();

    // 获取目标属性元信息
    PropertyInfo property = typeof(T).GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
    if (property == null)
    {
        throw new ArgumentException($"类型 {typeof(T).Name} 中不存在名为 {propertyName} 的公共实例属性", nameof(propertyName));
    }

    // 校验属性类型与返回值类型是否兼容
    if (!typeof(TProperty).IsAssignableFrom(property.PropertyType))
    {
        throw new ArgumentException($"属性 {propertyName} 的类型 {property.PropertyType.Name} 无法转换为 {typeof(TProperty).Name}", nameof(propertyName));
    }

    // 遍历提取属性值
    foreach (var item in list)
    {
        if (item == null)
        {
            result.Add(default);
            continue;
        }
        TProperty value = (TProperty)property.GetValue(item);
        result.Add(value);
    }

    return result;
}

调用泛型版本会更简洁:

var a1Values = GetGenericData<ABC, int>(listABC, "A1");

注意事项

  • 反射有一定性能开销,如果是高频调用场景,可以缓存PropertyInfo对象(比如用静态字典存类型+属性名对应的PropertyInfo)
  • 如果需要提取私有属性,可以修改BindingFlags为BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,但要注意访问权限的合规性
  • 代码中加入了空值校验和类型校验,避免运行时出现意外异常

内容的提问来源于stack exchange,提问作者Howard Teoh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:56:11