使用Json.NET进行Bson数组(de)序列化

Xav*_*nas 8 json.net bson

我只是尝试使用Json.NET以Bson格式序列化和反序列化字符串数组,但以下代码失败:

var jsonSerializer = new JsonSerializer();
var array = new string [] { "A", "B" };

// Serialization
byte[] bytes;
using (var ms = new MemoryStream())
using (var bson = new BsonWriter(ms))
{
    jsonSerializer.Serialize(bson, array, typeof(string[]));
    bytes = ms.ToArray();
}

// Deserialization
using (var ms = new MemoryStream(bytes))
using (var bson = new BsonReader(ms))
{
    // Exception here
    array = jsonSerializer.Deserialize<string[]>(bson);
}
Run Code Online (Sandbox Code Playgroud)

异常消息:

无法将当前JSON对象(例如{"name":"value"})反序列化为类型'System.String []',因为该类型需要JSON数组(例如[1,2,3])才能正确反序列化.

要修复此错误,请将JSON更改为JSON数组(例如[1,2,3])或更改反序列化类型,使其成为普通的.NET类型(例如,不是像整数这样的基本类型,而不是类似的集合类型可以从JSON对象反序列化的数组或List.JsonObjectAttribute也可以添加到类型中以强制它从JSON对象反序列化.

我怎样才能让它发挥作用?

Jam*_*ing 17

在BsonReader上将ReadRootValueAsArray设置为true

http://james.newtonking.com/projects/json/help/index.html?topic=html/P_Newtonsoft_Json_Bson_BsonReader_ReadRootValueAsArray.htm

此设置是必需的,因为BSON数据规范不保存有关根值是对象还是数组的元数据.


Bri*_*ers 6

嗯,从我坐的地方,你的代码应该可以工作,但Json.Net似乎认为你的序列化字符串数组是字典.这可能是因为,根据BSON规范,数组实际上会像对象一样被序列化为键值对列表.在这种情况下,键只是数组索引值的字符串表示.

无论如何,我能够通过几种不同的方式解决这个问题:

  1. 反序列化为Dictionary,然后手动将其转换回数组.

    var jsonSerializer = new JsonSerializer();
    var array = new string[] { "A", "B" };
    
    // Serialization
    byte[] bytes;
    using (var ms = new MemoryStream())
    using (var bson = new BsonWriter(ms))
    {
        jsonSerializer.Serialize(bson, array);
        bytes = ms.ToArray();
    }
    
    // Deserialization
    using (var ms = new MemoryStream(bytes))
    using (var bson = new BsonReader(ms))
    {
        var dict = jsonSerializer.Deserialize<Dictionary<string, string>>(bson);
        array = dict.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToArray();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将数组包装在外部对象中.

    class Wrapper
    {
        public string[] Array { get; set; }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后使用包装器对象进行序列化和反序列化.

    var jsonSerializer = new JsonSerializer();
    var obj = new Wrapper { Array = new string[] { "A", "B" } };
    
    // Serialization
    byte[] bytes;
    using (var ms = new MemoryStream())
    using (var bson = new BsonWriter(ms))
    {
        jsonSerializer.Serialize(bson, obj);
        bytes = ms.ToArray();
    }
    
    // Deserialization
    using (var ms = new MemoryStream(bytes))
    using (var bson = new BsonReader(ms))
    {
        obj = jsonSerializer.Deserialize<Wrapper>(bson);
    }
    
    Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • @XavierPoinas第二个解决方案,将数组包装在外部对象中,适用于未知类型.只需更改包装类的属性类型,即`public object Value {get; 组; }`而不是`public string [] Array {get; 组; 你可以将它与任何非数组类型一起使用.创建一个自动包装/解包的辅助类很容易. (2认同)