gpt4 book ai didi

c# - 反序列化接口(interface)集合时,使用自定义转换器从以前的数据模型反序列化 JSON 失败

转载 作者:行者123 更新时间:2023-11-30 18:21:25 26 4
gpt4 key购买 nike

我负责维护一个游戏系统,用户可以在该系统中将 JSON 序列化的 POCO 保存在本地缓存中以保存状态,例如 Character。 .

最新版本的代码改变了这些序列化对象的数据模型。特别是,创建了一个新界面。这在将字符的旧副本反序列化为新代码时会产生问题。我正尝试使用自定义转换器解决这些问题,但遇到了麻烦。

旧的序列化版本:

public class Character{
public Skill Parent {get;set;}
public Dictionary<string,Skill} Skills {get;set;}
}

public class Skill {
//normal stuff here.
}

新版本:

public class Character{
[JsonProperty, JsonConverter(typeof(ConcreteTypeConverter<Dictionary<string,Skill>>))]
public Dictionary<string,ISkill} Skills {get;set;}
}

public class Skill:ISkill {
//normal stuff here.
}

public interface ISkill{
//stuff that all skill-like things have here
}

我进一步定义了一个自定义转换器类(已阅读 thisthis

但我在反序列化集合时仍然遇到了麻烦。

public class Extensions 
{

//a lot of serializer extensions here including the Deserialize method
private static readonly CustomSerializationBinder Binder = new CustomSerializationBinder();
private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
TypeNameHandling = TypeNameHandling.Objects,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
Binder = Binder,
};
}


public class CustomSerializationBinder : DefaultSerializationBinder
{


public override Type BindToType(string assemblyName, string typeName)
{

return base.BindToType(assemblyName, typeName);


}
}

public class ConcreteTypeConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer,value); // serialization isnt't the problem.
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (typeof (T)==typeof(Dictionary<string,Skill>))
{
var retVal = new object();
if (reader.TokenType == JsonToken.StartObject)
{
T instance = (T)serializer.Deserialize(reader, typeof(T)); //crashes here
retVal = new List<T>() { instance };
return retVal;
}
}

return serializer.Deserialize<T>(reader);
}

public override bool CanConvert(Type objectType)
{
return true; // kind of a hack
}
}

所以我有一个旧的 Dictionary<string,Skill>我无法将其转换为 Dictionary<string,ISkill>在我能看到的任何代码路径中。我该如何解决?

最佳答案

由于您的遗留 JSON 已经包含所有对象(包括字典对象)的类型信息,您需要做的是剥离字典的类型信息,并允许反序列化的字典类型由代码控制,而不是 JSON。

下面的转换器应该完成这项工作:

public class IgnoreDictionaryTypeConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.GetDictionaryKeyValueTypes().Count() == 1;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
existingValue = existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
var obj = JObject.Load(reader);
obj.Remove("$type");
using (var subReader = obj.CreateReader())
{
serializer.Populate(subReader, existingValue);
}
return existingValue;
}

public override bool CanWrite { get { return false; } }

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

public static class TypeExtensions
{
/// <summary>
/// Return all interfaces implemented by the incoming type as well as the type itself if it is an interface.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<Type> GetInterfacesAndSelf(this Type type)
{
if (type == null)
throw new ArgumentNullException();
if (type.IsInterface)
return new[] { type }.Concat(type.GetInterfaces());
else
return type.GetInterfaces();
}

public static IEnumerable<Type[]> GetDictionaryKeyValueTypes(this Type type)
{
foreach (Type intType in type.GetInterfacesAndSelf())
{
if (intType.IsGenericType
&& intType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
{
yield return intType.GetGenericArguments();
}
}
}
}

然后你可以在设置中添加它,或者将它应用到有问题的字典属性中:

public class Character
{
[JsonConverter(typeof(IgnoreDictionaryTypeConverter))]
public IDictionary<string, ISkill> Skills { get; set; }
}

对于 future ,您可能还希望禁用字典的类型信息的发出,因为字典是集合,并且集合类型最好由代码指定,而不是 JSON:

public class Character
{
[JsonConverter(typeof(IgnoreDictionaryTypeConverter))]
[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public IDictionary<string, ISkill> Skills { get; set; }
}

关于c# - 反序列化接口(interface)集合时,使用自定义转换器从以前的数据模型反序列化 JSON 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35491265/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com