【问题标题】:Serialization of properties in JSON.NET throws ExceptionJSON.NET 中的属性序列化抛出异常
【发布时间】:2014-07-09 01:14:59
【问题描述】:

这是一个示例应用程序,它显示了使用 JsonConverter 对 List 进行自定义序列化。我用 JsonConvert 注册了一个自定义的 JsonSerializerSettings。这些设置安装了我的 ListOfGuidConverter。

当您将 List 作为序列化的根对象进行序列化和反序列化时,这非常有效。一旦你有一个不同的根对象并且 List 是一个属性,JSON.Net 就会抛出异常,说意外结束。

我能做些什么来解决这个问题?

感谢里奇

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using PB8.Peep;

namespace JsonTest
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var ListOfGuidsConverter = new ListJsonConverter<Guid>();
                var jss = new JsonSerializerSettings();
                jss.Converters.Add(new ListofGuidJsonConverter());

                string value1 = JsonConvert.SerializeObject(GetSampleList());
                Console.WriteLine(value1);

                JsonConvert.DefaultSettings = () => jss;

                string value2 = JsonConvert.SerializeObject(GetSampleList());
                Console.WriteLine();
                Console.WriteLine(value2);

                var value3 = JsonConvert.DeserializeObject<List<Guid>>(value2);

                string value4 = JsonConvert.SerializeObject(value3);

                Console.WriteLine();
                Console.WriteLine(value4);

                var value5 = JsonConvert.SerializeObject(GetSample());
                Console.WriteLine();
                Console.WriteLine(value5);

                var value6 = JsonConvert.DeserializeObject<Sample>(value5);

                var value7 = JsonConvert.SerializeObject(value6);

                Console.WriteLine();
                Console.WriteLine(value7);

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            finally
            {
                Console.ReadLine();
            }
        }

        public static List<Guid> GetSampleList()
        {
            return new List<Guid>
            {
                Guid.NewGuid(),
                Guid.NewGuid(),
                Guid.NewGuid()
            };
        }

        public static Sample GetSample()
        {
            Sample s = new Sample();
            s.List1.Add(Guid.NewGuid());
            s.List1.Add(Guid.NewGuid());
            s.List1.Add(Guid.NewGuid());
            s.List1.Add(Guid.NewGuid());
            s.List1.Add(Guid.NewGuid());

            return s;
        }

        public class Sample
        {
            public Sample()
            {
                List1 = GetSampleList();
            }

            public List<Guid> List1 { get; set; }
        }
    }




    public class ListofGuidJsonConverter : JsonConverter
    {
        private const string CapacityPropertyName = "c";
        private const string ListPropertyName = "l";
        private static readonly Type _type = typeof(List<Guid>);

        public override bool CanConvert(Type objectType)
        {
            bool canConvert = objectType == _type;
            return canConvert;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            const int DefaultCapacity = 4;

            if (reader.TokenType == JsonToken.StartObject)
                reader.Read();

            if (reader.TokenType == JsonToken.PropertyName)
                reader.Read();

            int capacity = DefaultCapacity;
            if (reader.TokenType == JsonToken.Integer)
            {
                capacity = Convert.ToInt32(reader.Value);
                reader.Read();
            }

            var listOfT = new List<Guid>(capacity);

            if (reader.TokenType == JsonToken.PropertyName)
                reader.Read();

            if (reader.TokenType == JsonToken.StartArray)
                reader.Read();

            for (int i = 0; i < capacity; i++)
            {
                var item = new Guid(Convert.ToString(reader.Value));
                listOfT.Add(item);
                reader.Read();
            }

            if (reader.TokenType == JsonToken.EndArray)
                reader.Read();

            if (reader.TokenType == JsonToken.EndObject)
                reader.Read();

            return listOfT;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var listOfT = (List<Guid>)value;

            writer.WriteStartObject();

            writer.WritePropertyName(CapacityPropertyName);
            writer.WriteValue(listOfT.Count);

            writer.WritePropertyName(ListPropertyName);
            writer.WriteStartArray();

            foreach (var item in listOfT)
                writer.WriteValue(item);

            writer.WriteEndArray();

            writer.WriteEndObject();
        }
    }
}

【问题讨论】:

    标签: c# json serialization json.net


    【解决方案1】:

    在实现 JsonConverter 时,很容易让阅读器逻辑出错。很可能你在某个地方读了太多次,这会在以后丢弃序列化程序。我建议不要试图找出它偏离轨道的地方,而是采用不同的方法:在转换器内部使用更高级别的 LINQ-to-JSON API (JObjects),并让它与读者打交道。您的代码将更短,更易于理解/维护。

    这是使用 LINQ-to-JSON 的转换器的替代实现。它通过了你所有的测试。

    public class ListofGuidJsonConverter : JsonConverter
    {
        private const string CapacityPropertyName = "c";
        private const string ListPropertyName = "l";
    
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(List<Guid>));
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject obj = JObject.Load(reader);
            int capacity = obj[CapacityPropertyName].Value<int>();
            List<Guid> list = new List<Guid>(capacity);
            foreach (JToken token in obj[ListPropertyName].Children())
            {
                list.Add(new Guid(token.ToString()));
            }
            return list;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            List<Guid> list = (List<Guid>)value;
            JObject obj = new JObject();
            obj.Add(CapacityPropertyName, list.Count);
            JArray array = new JArray();
            foreach (Guid guid in list)
            {
                array.Add(guid.ToString());
            }
            obj.Add(ListPropertyName, array);
            obj.WriteTo(writer);
        }
    }
    

    【讨论】:

    • 太棒了!这似乎已经解决了。我通常不是 LINQ 的粉丝,但我真的很喜欢这里的实现。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-12
    • 1970-01-01
    相关资源
    最近更新 更多