我正在重构对后向兼容性至关重要的遗留代码。我一直在尝试为 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);
}
//..
}
对于更短的代码,您可以使用:
var firstArgumentType = GetFirstArgumentType(value.GetType());
newList = value.ConvertAll(x => Convert.ChangeType(x, _typeToProxy[firstArgumentType]));
但是,您需要为此更改更多代码。 我可以在这个网站上给你一个工作示例: https://dotnetfiddle.net/4CmvzR
也可以在本站运行代码
我想,多亏了你的建议和帮助,我解决了这个问题。
编辑:我使用动态类型来跳过类型检查,并使用反射方法获取类型。类型转换是通过包装方法 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);
}
}