我只是尝试使用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);
}
异常消息:
无法将当前JSON对象(例如{&#34; name&#34;:&#34; value&#34;})反序列化为类型&#39; System.String []&#39;因为该类型需要JSON数组(例如[1,2,3])才能正确反序列化。
要修复此错误,请将JSON更改为JSON数组(例如[1,2,3])或更改反序列化类型,使其成为普通的.NET类型(例如,不是像整数这样的基本类型,而不是可以从JSON对象反序列化的集合类型,如数组或List)。 JsonObjectAttribute也可以添加到类型中以强制它从JSON对象反序列化。
我怎样才能让它发挥作用?
答案 0 :(得分:16)
在BsonReader上将ReadRootValueAsArray设置为true
此设置是必需的,因为BSON数据规范不会保存有关根值是对象还是数组的元数据。
答案 1 :(得分:6)
无论如何,我能够通过几种不同的方式解决这个问题:
反序列化为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();
}
将数组包装在外部对象中。
class Wrapper
{
public string[] Array { get; set; }
}
然后使用包装器对象进行序列化和反序列化。
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);
}
希望这有帮助。
答案 2 :(得分:1)
如this answer的James Newton-King所述,BSON格式不会保存有关根值是否为集合的元数据,因此有必要在开始反序列化之前适当地设置BsonDataReader.ReadRootValueAsArray
当反序列化为某种已知的POCO类型(而不是dynamic
或JToken
)时,一种简单的方法是根据根类型是否为使用array contract进行序列化。以下扩展方法可以做到这一点:
public static partial class BsonExtensions
{
public static T DeserializeFromFile<T>(string path, JsonSerializerSettings settings = null)
{
using (var stream = new FileStream(path, FileMode.Open))
return Deserialize<T>(stream, settings);
}
public static T Deserialize<T>(byte [] data, JsonSerializerSettings settings = null)
{
using (var stream = new MemoryStream(data))
return Deserialize<T>(stream, settings);
}
public static T Deserialize<T>(byte [] data, int index, int count, JsonSerializerSettings settings = null)
{
using (var stream = new MemoryStream(data, index, count))
return Deserialize<T>(stream, settings);
}
public static T Deserialize<T>(Stream stream, JsonSerializerSettings settings = null)
{
// Use BsonReader in Json.NET 9 and earlier.
using (var reader = new BsonDataReader(stream) { CloseInput = false }) // Let caller dispose the stream
{
var serializer = JsonSerializer.CreateDefault(settings);
//https://www.newtonsoft.com/json/help/html/DeserializeFromBsonCollection.htm
if (serializer.ContractResolver.ResolveContract(typeof(T)) is JsonArrayContract)
reader.ReadRootValueAsArray = true;
return serializer.Deserialize<T>(reader);
}
}
}
现在您可以轻松地做到:
var newArray = BsonExtensions.Deserialize<string []>(bytes);
注意:
BSON支持已移至Json.NET Newtonsoft.Json.Bson
中自己的软件包10.0.1。在此版本和更高版本中,BsonDataReader
取代了现在已经过时的BsonReader
。
可以使用相同的扩展方法对字典进行反序列化,例如:
var newDictionary = BsonExtensions.Deserialize<SortedDictionary<int, string>>(bytes);
通过检查合同类型ReadRootValueAsArray
是否设置正确。
演示小提琴here。
答案 3 :(得分:0)
通常,在将ReadRootValueAsArray设置为true之前,您可以先检查数据类型,如下所示:
if (typeof(IEnumerable).IsAssignableFrom(type))
bSonReader.ReadRootValueAsArray = true;
答案 4 :(得分:0)
我知道这是一个旧线程,但我发现使用MongoDB.Driver的强大功能时很容易反序列化
您可以使用BsonDocument.parse(JSONString)反序列化JSON对象,以便反序列化字符串数组使用:
string Jsonarray = "[\"value1\", \"value2\", \"value3\"]";
BsonArray deserializedArray = BsonDocument.parse("{\"arr\":" + Jsonarray + "}")["arr"].asBsonArray;
deserializedArray可以用作任何数组,例如foreach循环。