使用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);            
    }
...
}

使用JSON反序列化时如何将对象类型更改为另一种类型.Net或调用默认序列化器

一旦对象类型被推断出来并且对象已经被实例化,您就可以使用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类。