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

如何将List<KeyValuePair<string,string>>转换为自定义实体类?解决可空类型问题

问题分析与解决方案

首先,你的代码存在两个核心问题:

  1. 错误获取属性类型:你使用了 pro.GetType(),这会返回 PropertyInfo 类型,而非属性本身的类型。正确的做法是使用 pro.PropertyType。
  2. Nullable 类型判断逻辑错误:
    • 对于引用类型(如 string),string? 只是编译时的可空注解,运行时它和 string 是同一个类型,因此 typeof(string?) 等价于 typeof(string),无法通过 typeof 区分。
    • 对于值类型(如 int),int? 是 Nullable<int> 的语法糖,运行时是一个独立的泛型类型,所以 typeof(int?) 能正确识别。

接下来是修复后的完整代码:

private T GetItem<T>(List<KeyValuePair<string, string>> item) where T : new()
{
    Type modelType = typeof(T);
    T obj = new T(); // 替换Activator.CreateInstance<T>(),更简洁且有编译时检查

    foreach (PropertyInfo prop in modelType.GetProperties())
    {
        // 查找对应Key的值
        var kvp = item.FirstOrDefault(x => x.Key.Equals(prop.Name, StringComparison.OrdinalIgnoreCase));
        string? val = kvp.Value;
        
        // 处理API返回的"NULL"字符串
        if (string.Equals(val, "NULL", StringComparison.OrdinalIgnoreCase))
            val = null;

        Type propType = prop.PropertyType;

        // 处理字符串类型(包括string?)
        if (propType == typeof(string))
        {
            prop.SetValue(obj, val);
            continue;
        }

        // 处理可空值类型(如int?)
        Type? underlyingType = Nullable.GetUnderlyingType(propType);
        if (underlyingType != null)
        {
            if (val == null)
            {
                prop.SetValue(obj, null);
            }
            else if (TryParseValue(val, underlyingType, out object? parsedValue))
            {
                prop.SetValue(obj, parsedValue);
            }
            else
            {
                prop.SetValue(obj, null);
            }
            continue;
        }

        // 处理非可空值类型(如int)
        if (propType.IsValueType)
        {
            if (TryParseValue(val, propType, out object? parsedValue))
            {
                prop.SetValue(obj, parsedValue);
            }
            else
            {
                // 解析失败时设置类型默认值(如int默认0)
                prop.SetValue(obj, Activator.CreateInstance(propType));
            }
        }
    }

    return obj;
}

// 通用解析方法,支持基础值类型
private bool TryParseValue(string? input, Type targetType, out object? result)
{
    result = null;
    if (input == null)
        return false;

    try
    {
        result = Convert.ChangeType(input, targetType);
        return true;
    }
    catch (FormatException)
    {
        return false;
    }
}

关键改进点说明:

  • 替换类型获取方式:用 prop.PropertyType 替代 pro.GetType(),正确获取属性的实际类型。
  • 统一处理字符串可空:直接判断 propType == typeof(string),因为 string? 在运行时和 string 无区别,只需确保 val 为 null 时正确赋值。
  • 通用可空值类型处理:通过 Nullable.GetUnderlyingType 判断是否为可空值类型,统一解析逻辑。
  • 新增通用解析方法:TryParseValue 复用解析逻辑,支持更多基础值类型(如 long、bool 等),避免重复代码。
  • 优化实例创建:使用 new T() 并添加 where T : new() 约束,比 Activator.CreateInstance<T>() 更高效且有编译时检查。
  • 忽略大小写的Key匹配:使用 StringComparison.OrdinalIgnoreCase 避免因大小写不一致导致的匹配失败(可根据需求调整)。

针对你的疑问补充:

为什么 int? 能用 typeof 判断而 string? 不行?

  • int 是值类型,int? 本质是 Nullable<int> 结构体,属于不同的运行时类型。
  • string 是引用类型,string? 只是编译阶段的注解,用于提示编译器进行空值检查,运行时没有对应的新类型,因此 typeof(string?) 和 typeof(string) 返回同一个 Type 对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 08:18:35