JSON.NET中的属性序列化会引发异常

时间:2014-07-09 01:14:59

标签: c# json serialization json.net

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

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

我该怎么做才能解决这个问题?

谢谢Rich

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();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

在实现JsonConverter时,很容易让读者逻辑错误。很可能你在线上的某个地方读了太多次,这就是以后抛弃序列化器。我建议采用不同的方法,而不是试图找出它离开轨道的位置:在转换器中使用更高级别的LINQ-to-JSON API(JObject),让它与读者打交道。您的代码将更短,更容易理解/维护。

以下是使用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);
    }
}