首页 > 解决方案 > Newtonsoft C# 自定义 JsonConverter 不反序列化字节数组

问题描述

我正在尝试创建一个简单的 JsonConverter。我希望将我的字节数组序列化为数字数组,而不是默认的 base 64 字符串。但是,当我尝试这样做时,我得到了 JsonSerializationException。

这是我为简化问题而制作的课程:

public class SomethingFancy
{
    string name;
    byte[] usefulData;

    public SomethingFancy(string name, byte[] usefulData)
    {
        this.Name = name;
        this.UsefulData = usefulData;
    }

    public string Name { get => name; set => name = value; }
    public byte[] UsefulData { get => usefulData; set => usefulData = value; }
}

现在这是我的自定义 Json 转换器。我试图让它只适用于 IEnumerable 对象。(默认情况下,序列化时 IEnumerable 转换为字符串,反序列化时反之亦然。我更改了该行为以将 IEnumerable 保存为 json 数字数组。

public class EnumerableByteConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        var result = typeof(IEnumerable<byte>).IsAssignableFrom(objectType);
        return result;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            writer.WriteValue(value);
        }
        else
        {
            byte[] bytes = ((IEnumerable<byte>)value).ToArray();
            int[] ints = Array.ConvertAll(bytes, c => (int)c);

            writer.WriteStartArray();
            foreach (int number in ints)
            {
                writer.WriteValue(number);
            }
            writer.WriteEndArray();
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        int[] ints = (int[])reader.Value;
        if (ints == null)
            return default;
        else
        {
            byte[] bytes = ints.SelectMany(BitConverter.GetBytes).ToArray();
            if (objectType == typeof(byte[]))
            {
                return bytes;
            }
            var result = new List<byte>(bytes);
            return result;
        }
    }
}

这是我为测试我的课程而编写的一些单元测试:

[TestClass]
public class PersistencyServiceTest
{
    [TestMethod]
    public void TestJsonSerializationDeserialization()
    {
        var settings = new JsonSerializerSettings();
        settings.Converters.Add(new EnumerableByteConverter());

        SomethingFancy something = new SomethingFancy("someName", new byte[3] { 1, 2, 3 });

        string dataasstring = JsonConvert.SerializeObject(something, Formatting.Indented, settings);

        something = JsonConvert.DeserializeObject<SomethingFancy>(dataasstring, settings);

        Assert.IsTrue(something != null);
        Assert.IsTrue(something.Name == "someName");
        Assert.IsTrue(something.UsefulData != null);
        Assert.IsTrue(something.UsefulData[0] == 1);
        Assert.IsTrue(something.UsefulData[1] == 2);
        Assert.IsTrue(something.UsefulData[2] == 3);
    }
}

现在,它按照我的需要序列化我的对象。

{
  "Name": "someName",
  "UsefulData": [
    1,
    2,
    3
  ]
}

但是,反序列化会引发 JsonSerializationException(反序列化对象时出现意外标记:整数。路径 'UsefulData[0],第 4 行,第 5 位)。

我错过了什么?

谢谢你的帮助。

标签: c#jsonjson.net

解决方案


我用 ReadJson 方法做错了。

这是我遇到的同样问题的人的自定义 JsonConverter:

public class EnumerableByteConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        var result = typeof(IEnumerable<byte>).IsAssignableFrom(objectType);
        return result;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            writer.WriteValue(value);
        }
        else
        {
            byte[] bytes = ((IEnumerable<byte>)value).ToArray();
            int[] ints = Array.ConvertAll(bytes, c => (int)c);

            writer.WriteStartArray();
            foreach (int number in ints)
            {
                writer.WriteValue(number);
            }
            writer.WriteEndArray();
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        List<int> ints = null;
        if (reader.TokenType == JsonToken.Null)
            return default;
        while (reader.TokenType != JsonToken.EndArray)
        {
            if (reader.TokenType == JsonToken.StartArray)
            {
                ints = new List<int>();
                reader.Read();
            }
            else if(reader.TokenType == JsonToken.Integer)
            {
                ints.Add(Convert.ToInt32(reader.Value));
                reader.Read();
            }
            else
            {
                throw new InvalidOperationException();
            }
        }
        if (ints == null)
            return default;
        else
        {
            byte[] bytes = Array.ConvertAll(ints.ToArray(), x => (byte)x);
            if (objectType == typeof(byte[]))
            {
                return bytes;
            }
            var result = new List<byte>(bytes);
            return result;
        }
    }
}

推荐阅读