使用JSON反序列化时如何将对象类型更改为另一种类型.Net或调用默认序列化器
本文关键字:类型 Net 另一种 调用 序列化 默认 反序列化 JSON 对象 使用 | 更新日期: 2023-09-27 18:05:02
序列化时,我将ClassName写入对象的_CurrentClassName属性。当读取json与json。. Net库,我需要从这个属性更改对象值。
{
"Field1": 0,
"Field2": "34",
"_CurrentClassName": "MyCustomClass"
}
class CustomJsonConverter : JsonConverter
{
...
public override bool CanConvert(Type objectType)
{
return objectType.IsClass;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var value = existingValue;
if (reader.TokenType == JsonToken.Null)
{
return null;
}
else if (reader.TokenType == JsonToken.StartObject)
{
JObject jObject = JObject.Load(reader);
JToken jToken;
if (jObject.TryGetValue("_CurrentClassName", out jToken))
{
var t = jToken.Value<string>();
Type tt = Type.GetType(objectType.Namespace + "." + t);
value = Activator.CreateInstance(tt);
return value;
}
}
return serializer.Deserialize(reader);
}
...
}
一旦对象类型被推断出来并且对象已经被实例化,您就可以使用JsonSerializer.Populate(jObject.CreateReader())
来填充它。
public abstract class CustomJsonConverterBase : JsonConverter
{
protected abstract Type InferType(JToken token, Type objectType, object existingValue);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var token = JToken.Load(reader);
var actualType = InferType(token, objectType, existingValue);
if (existingValue == null || existingValue.GetType() != actualType)
{
var contract = serializer.ContractResolver.ResolveContract(actualType);
existingValue = contract.DefaultCreator();
}
using (var subReader = token.CreateReader())
{
// Using "populate" avoids infinite recursion.
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 class CustomJsonConverter : CustomJsonConverterBase
{
public const string ClassPropertyName = @"_CurrentClassName";
protected override Type InferType(JToken token, Type objectType, object existingValue)
{
if (token is JObject)
{
var typeName = (string)token[ClassPropertyName];
if (typeName != null)
{
var actualType = Type.GetType(objectType.Namespace + "." + typeName);
if (actualType != null)
return actualType;
}
}
return objectType;
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
CustomCreationConverter<T>
也使用serializer.Populate()
来填充刚刚分配的对象,所以这是解决这个问题的标准方法。
请注意,您正在部分复制Json。. NET的内置TypeNameHandling
功能
如果您不与_CurrentClassName
属性名称或其值语法结婚,您可以使用Json。Net内建的类型处理。
当序列化或反序列化时,你可以传入一个JsonSerializerSettings
对象来控制序列化或反序列化。
在这个对象上,你可以设置一个TypeNameHandling
属性来控制Json如何。Net序列化和反序列化正在处理的确切类型。
下面是一个LINQPad示例:
void Main()
{
var t = new Test { Key = 42, Value = "Meaning of life" };
var json = JsonConvert.SerializeObject(
t, Newtonsoft.Json.Formatting.Indented,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
Console.WriteLine(json);
var obj =JsonConvert.DeserializeObject(json,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
Console.WriteLine(obj.GetType().FullName);
}
public class Test
{
public int Key { get; set; }
public string Value { get; set; }
}
输出:{
"$type": "UserQuery+Test, LINQPadQuery",
"Key": 42,
"Value": "Meaning of life"
}
UserQuery+Test
这里可以看到反序列化返回的对象类型是Test
类。