newtonsoft json反序列化的问题(崩溃)

时间:2020-06-08 15:34:37

标签: c# json json.net

我正在尝试使用自定义JsonConverter按照对 How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects? 的答案中所示的方法,对多态类型层次结构进行序列化和反序列化。但是,当我调用转换器的ReadJson()方法反序列化一些我先前序列化的JSON时,它崩溃了。如何使用转换器反序列化JSON?

以下代码重现了该问题。它是多态类型层次结构中只有一个子类型的原始代码的简化。

using System;
using System.IO;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace testJSON
{
    class               Program
    {
        public List< Ente > ListaEntes = new List< Ente >(); 

        static void Main(string[] args)
        {
            Program program = new Program();
            program.ListaEntes.Add( new Enemy( 10 ) );
            program.ListaEntes.Add( new Enemy( 20 ) );

            JsonSerializer serializer = new JsonSerializer();
            serializer.TypeNameHandling = TypeNameHandling.Objects;
            serializer.Formatting = Formatting.Indented;

            string folder = "C:\\Users\\pablo\\PasotaPV8_data\\archivoPrueba.dat";
            StreamWriter sw = new StreamWriter( @folder );
            JsonWriter writer = new JsonTextWriter( sw );
            serializer.Serialize( writer, program.ListaEntes );
            writer.Close();
            sw.Close();

            program.ListaEntes.Clear();

            StreamReader sr = new StreamReader( @folder );
            JsonEnteConverter jsonEnteConverter = new JsonEnteConverter();
            JsonReader reader = new JsonTextReader( sr );

            program.ListaEntes = ( List< Ente > ) jsonEnteConverter.ReadJson( reader, null, null, serializer );

        }
    }

    public class        Ente
    {
        public string tipo;
        public Animator animator;
    }

    public class        Enemy : Ente
    {
        public          Enemy()
        {
            animator = new Animator( this );
        }

        public          Enemy( int pVar )
        {
            tipo = "enemigo";
        }
    }

    public class        Animator
    {
        Ente father;

        public          Animator( Enemy pEnemy )
        {
            father = pEnemy;
        }
    }

    public class        JsonEnteConverter : Newtonsoft.Json.Converters.CustomCreationConverter< Ente >
    {
        public override Ente Create( Type objectType )
        {
            throw new NotImplementedException();
        }

        public          Ente Create( JObject jObject )
        {
            string type = jObject.Property( "tipo" ).ToString(); //get property Type from your json

            switch ( type )
            {
                case "enemigo":
                    return new Enemy();
            }
            throw new ApplicationException(String.Format("Type not found", type));
        }

        public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
        {
            JObject jObject = JObject.Load( reader );
            var targetObject = Create( jObject );
            serializer.Populate( jObject.CreateReader(), targetObject );
            return targetObject;
        }
    }
}

错误:

未处理的异常。 Newtonsoft.Json.JsonReaderException:从JsonReader读取JObject时出错。当前JsonReader项不是对象:StartArray。路径“,行 1,位置1。 在Newtonsoft.Json.Linq.JObject.Load(JsonReader reader,JsonLoadSettings设置) 在Newtonsoft.Json.Linq.JObject.Load(JsonReader reader) 在testJSON.JsonEnteConverter.ReadJson(JsonReader reader,Type objectType,Object existValue,JsonSerializer serializer)在C:\ proyectos \ proyectosC#\ bugJSON \ Program.cs:line 90 在C:\ proyectos \ proyectosC#\ bugJSON \ Program.cs:line 35中的testJSON.Program.Main(String [] args)中

演示小提琴在这里重现了问题:https://dotnetfiddle.net/cbjYMw

1 个答案:

答案 0 :(得分:1)

您在这里遇到一些问题:

  1. 您的基本问题是,您尝试通过直接调用List<Ente>JsonEnteConverter.ReadJson()进行反序列化,但是JsonEnteConverter旨在对{em的单个实例进行反序列化1}},而不是它们的集合。这会导致您看到的异常。

    相反,您需要将Ente添加到JsonSerializerSettings.Converters,从设置中制造一个JsonEnteConverter,然后使用它来反序列化JsonSerializer,如下所示:

    List<Ente>
  2. var readSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, Converters = { new JsonEnteConverter() }, // FIXED }; using (var sr = new StreamReader( @folder )) // FIXED dispose of readers properly using (var reader = new JsonTextReader( sr )) { ListaEntes = JsonSerializer.Create(readSettings).Deserialize<List<Ente>>(reader); } 中,您尝试通过调用JsonEnteConverter.Create()来检查"tipo"属性的值。但是,JObject.Property(string)返回与组合的名称/值对相对应的指定名称的JProperty。因此,字符串值的值为jObject.Property( "tipo" ).ToString();

    相反,您只需要执行"tipo": "enemigo"就可以得到值:

    var type = (string)jObject["tipo"]
  3. public Ente Create( JObject jObject ) { var type = (string)jObject["tipo"]; // FIXED switch ( type ) { case "enemigo": return new Enemy(); } throw new ApplicationException(String.Format("Type not found", type)); } StreamWriterJsonTextWriterStreamReader都是一次性的,因此应通过using语句进行适当处理,例如如上所示。

  4. 由于您正在使用JsonTextReader类型层次结构的自定义创建转换器,因此可能不需要使用TypeNameHandling。但是,如果这样做,出于安全原因,出于 custom ISerializationBinder 中所述的原因,您应该考虑编写TypeNameHandling caution in Newtonsoft Json

演示小提琴在这里显示有效的Entehttps://dotnetfiddle.net/VNL5PN

相关问题