使用Dictionary<T>将List<U>转换为List<Type, Type>,类型分别对应T和U

问题描述 投票:0回答:2

我正在重构对后向兼容性至关重要的遗留代码。我一直在尝试为 40 多种要序列化的不同类型开发一个转换器。

我需要将

List<T>
s转换为
List<U>
s,其中
U = TypeDictionary<Type,Type>[T]
.

我做了很多搜索,并在这个问题上工作了两天。我仍然无法找到答案,可能是因为不知道正确的关键字,我感到迷路了。如果有任何建议,我将不胜感激。

这是我用来复制类属性的静态类:

public static class PropertyCopier
    {
        public static U CopyFrom<T, U>(T source, U target)
        {
            var targetObj = Activator.CreateInstance<U>();
            foreach (var targetProp in targetObj.GetType().GetProperties())
            {
                var sourceProp = source.GetType().GetProperty(targetProp.Name);
                if (sourceProp == null)
                {
                    var sourceField = source.GetType().GetField(targetProp.Name);
                    if (sourceField == null)
                    {
                        throw new Exception("there is no field or property with same name");
                    }
                    targetProp.SetValue(targetObj, sourceField.GetValue(source));
                }
                else
                {
                    targetProp.SetValue(targetObj, sourceProp.GetValue(source));
                }
            }
            return targetObj;
        }
    }

我使用 Json.Net 定义了一个类; “自定义类型转换器:JsonConverter”。 这三个私有方法和字典是CustomTypeConverter的成员:

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

private bool isGenericList(Type type)
    {
        return (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List<>)));
    }

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

private List<U> ConvertListToProxy<T, U>(List<T> source, U target)
    {
        var lst = source.Select(x => PropertyCopier.CopyFrom(x, target)).ToList();
        return lst;
    }

这是 CustomTypeConverter 的 WriteJson 方法的一部分

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
    //..
         if ( isGenericList(value.GetType()) )
            {
                Type listType = typeof(List<>);
                listType.MakeGenericType(GetFirstArgumentType(value.GetType()));
                var newVal = Convert.ChangeType(value, listType);
                var newList = ConvertListToProxy(newVal, TypeToProxy[value.GetType()]);
                serializer.Serialize(writer, newList);
            }
    //..
    }

这是显示错误信息的截图 enter image description here

c# generics json.net type-conversion system.reflection
2个回答
1
投票

对于更短的代码,您可以使用:

var firstArgumentType = GetFirstArgumentType(value.GetType());
newList = value.ConvertAll(x => Convert.ChangeType(x, _typeToProxy[firstArgumentType]));

但是,您需要为此更改更多代码。 我可以在这个网站上给你一个工作示例: https://dotnetfiddle.net/4CmvzR

也可以在本站运行代码


1
投票

我想,多亏了你的建议和帮助,我解决了这个问题。

编辑:我使用动态类型来跳过类型检查,并使用反射方法获取类型。类型转换是通过包装方法 PropertyCopier.ProxyFrom.

处理的
public List<dynamic> ConvertListToProxy(dynamic source)
    {
        // source is List<>
        Type T = source.GetType().GenericTypeArguments[0];
        Type U = _typeToProxy[T];
        List<dynamic> target = new List<dynamic>();
        try
        {
            foreach (dynamic item in source)
            {
                target.Add(PropertyCopier.ProxyFrom(item, U));
            }
        }
        catch (Exception ex)
        {                
            Logger.Get().WriteLine("***-Exception-***");
            Logger.Get().WriteLine($"***-Trying to convert to List<{U.Name}>");
            Logger.Get().WriteLine(ex.Message);
            Logger.Get().WriteLine($"-***");

        }
        return target;
    }

WriteJson 方法的调用部分修改如下:

 if (isGenericList(value.GetType()))
            {
                var newList = ConvertListToProxy(value);
                serializer.Serialize(writer, newList);
            }
            else
            {
                if (_types.Contains(type))
                {                    
                var newObj = PropertyCopier.CopyFrom(Convert.ChangeType(value, type), _typeToProxy[type]);
                serializer.Serialize(writer, newObj);
                }
            }
© www.soinside.com 2019 - 2024. All rights reserved.