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

重构遗留代码:将Object类型的List<T>转换为List<U>的实现求助

问题分析与修正方案

现有代码的核心问题

  1. MakeGenericType未接收返回值:原代码中listType.MakeGenericType(...)的结果没有赋值回变量,导致listType始终是开放泛型的List<>,而非具体的List<T>,直接引发Convert.ChangeType失败。
  2. 泛型方法调用不匹配:ConvertListToProxy是泛型方法,但调用时传入的newVal是object类型,无法自动推断泛型参数,导致运行时类型错误。
  3. TypeToProxy字典key错误:原代码用value.GetType()(即List的类型)作为字典key,但字典的映射逻辑是T→U(元素类型映射),应该用List的泛型参数类型作为key。
  4. PropertyCopier冗余参数:CopyFrom方法中的target参数未被使用,方法内部自行创建了U实例,属于冗余设计且易造成误解。

修正后的代码实现

1. 优化PropertyCopier类

public static class PropertyCopier
{
    // 移除冗余的target参数,添加new()约束简化实例创建
    public static U CopyFrom<T, U>(T source) where U : new()
    {
        var targetObj = new U();
        var targetType = typeof(U);
        var sourceType = typeof(T);

        foreach (var targetProp in targetType.GetProperties())
        {
            // 优先匹配属性
            var sourceProp = sourceType.GetProperty(targetProp.Name);
            if (sourceProp != null)
            {
                targetProp.SetValue(targetObj, sourceProp.GetValue(source));
                continue;
            }

            // 属性不存在时匹配字段
            var sourceField = sourceType.GetField(targetProp.Name);
            if (sourceField == null)
            {
                throw new InvalidOperationException($"未在类型 {sourceType.Name} 中找到名为 {targetProp.Name} 的属性或字段");
            }
            targetProp.SetValue(targetObj, sourceField.GetValue(source));
        }
        return targetObj;
    }
}

2. 修正CustomTypeConverter的核心方法

private Dictionary<Type, Type> TypeToProxy = new Dictionary<Type, Type>();

// 兼容更多List子类(可选,若仅处理原生List<>可保留原逻辑)
private bool isGenericList(Type type)
{
    return type.IsGenericType && 
           typeof(IList<>).IsAssignableFrom(type.GetGenericTypeDefinition());
}

private Type GetFirstArgumentType(Type type)
{
    return type.GetGenericArguments()[0];
}

// 移除冗余的target参数,依赖new()约束创建目标实例
private List<U> ConvertListToProxy<T, U>(List<T> source) where U : new()
{
    return source.Select(x => PropertyCopier.CopyFrom<T, U>(x)).ToList();
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    // ... 其他序列化逻辑 ...
    if (isGenericList(value.GetType()))
    {
        var sourceListType = value.GetType();
        var sourceElementType = GetFirstArgumentType(sourceListType);

        // 检查是否存在元素类型映射
        if (!TypeToProxy.TryGetValue(sourceElementType, out var targetElementType))
        {
            // 无映射时直接序列化原列表,避免崩溃
            serializer.Serialize(writer, value);
            return;
        }

        // 通过反射调用泛型转换方法(解决object类型无法推断泛型参数的问题)
        var convertMethod = typeof(CustomTypeConverter)
            .GetMethod(nameof(ConvertListToProxy), BindingFlags.NonPublic | BindingFlags.Instance)
            .MakeGenericMethod(sourceElementType, targetElementType);

        var targetList = convertMethod.Invoke(this, new[] { value });

        // 序列化转换后的目标列表
        serializer.Serialize(writer, targetList);
    }
    // ... 其他序列化逻辑 ...
}

关键修正说明

  • 反射调用泛型方法:由于输入的value是object类型,无法直接推断ConvertListToProxy的泛型参数,因此通过反射获取泛型方法定义,构造具体的T和U类型后调用。
  • 修正字典映射逻辑:改为用List的元素类型作为字典key,符合T→U的映射需求。
  • 增加异常安全处理:添加TryGetValue检查映射是否存在,避免无映射时抛出异常,提升代码鲁棒性。
  • 优化实例创建:利用where U : new()约束替代Activator.CreateInstance,提高性能和代码可读性。

内容的提问来源于stack exchange,提问作者Mustafa şentürk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 18:05:01