TL;DR
我正在尝试将 BSON 数据从 Julia/C# 序列化(反)序列化,一些库知道如何用每种语言编写和读取此数据,但我不知道如何在两种实现之间进行转换。
感觉应该使用 Json.net JSON 转换器,但我不知道如何在不为每种类型重写转换器的情况下配置它。
我不期望得到完整的答案,但有帮助的指示将不胜感激!
添加:这是一个有点接近的话题Json.NET 自定义 JsonConverter 与数据类型 https://stackoverflow.com/questions/36969500/json-net-custom-jsonconverter-with-data-types.
Context
Project
我目前正在研究使用 julia 的计算内核和充当图形界面的 .net 程序之间的通信。
为了能够在两个程序之间共享相当复杂的数据集,我寻找了一种数据格式
- 两种语言均受支持,
- 足够灵活,可以处理大量数据(例如复数的 ND 数组)
在尝试了 MsgPack(不幸的是,它还不适用于 ND 数组,哎呀!)之后,我现在正在测试 BSON 作为序列化格式。
我的目标是能够处理多种自定义类型,而无需每次都重写所有内容。
可用的库
在朱莉娅那里,有一个BSON.jl https://github.com/JuliaIO/BSON.jl包可以写入和读取几乎所有内容,所以我们假设它可以处理我扔给他的任何东西。
在本问题的主要对象 C# 中,有一个看似显而易见的选择:JSON.net BSON https://www.newtonsoft.com/json/help/html/SerializeToBson.htm序列化器。
Problem
尽管有可用的代码,julia 序列化器写入的信息当然是 Json.net 无法在本机序列化或反序列化的。
因此,在阅读了很多帖子之后,这似乎是一个习惯JsonConverter<T>
是实现我的目标所必需的。
很多帖子似乎已经可以做到这一点,但是:
- 我从未在 C#(或任何其他语言)中做过类似的事情
- 我不知道从哪里开始以避免不必要的代码重复
数据样本
以服务器为例,下面是使用 julia 包生成的 BSON 文件的 JSON 转换。转换是用https://json-bson-converter.appspot.com/ https://json-bson-converter.appspot.com/
{
"dict": {
"tag": "struct",
"type": {
"tag": "datatype",
"params": [
{
"tag": "datatype",
"params": [],
"name": [
"Core",
"Any"
]
},
{
"tag": "datatype",
"params": [],
"name": [
"Core",
"Any"
]
}
],
"name": [
"Main",
"Base",
"Dict"
]
},
"data": [
[
"string",
"arr",
"vec",
"cplxvec",
"scal"
],
[
"blablabla",
{
"tag": "array",
"type": {
"tag": "datatype",
"params": [],
"name": [
"Core",
"Int8"
]
},
"size": [
2,
3
],
"data": "683oIbTI"
},
{
"tag": "array",
"type": {
"tag": "datatype",
"params": [],
"name": [
"Core",
"Int8"
]
},
"size": [
4
],
"data": "KxgCgA=="
},
{
"tag": "array",
"type": {
"tag": "datatype",
"params": [
{
"tag": "datatype",
"params": [],
"name": [
"Core",
"Float64"
]
}
],
"name": [
"Main",
"Base",
"Complex"
]
},
"size": [
3
],
"data": "bODExAuj5D9SoKEy0NDqP4jU3buU8+k/tFNpqcmh7z+miGD4H87oPyKwK7BUEuo/"
},
33.6
]
]
}
}
据我分析该文件的内容,我看到:
- 标量类型被转换为某种本机格式
- Other types are converted to dictionary-like structures with the following properties
- a
tag
由单个字段组成string
- a
type
字段具有特定的格式,具体取决于内容tag
- a
data
以二进制格式编码的字段
- 一个可选的
size
字段(再次基于内容tag
- A
type
field is characterized by the following properties
- a
tag
像之前一样
- a
params
field that may be
- a
name
列出 Julia 的类型名称的字段
定制转换器
我知道要制作自定义转换器,起点如下,基于例如here https://blog.maskalik.com/asp-net/json-net-implement-custom-serialization/ :
public class JuliaObjectSerializer : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
然而,我真的不知道要定义什么才能足够通用和通用,以便从我的源文件中读取所有信息。
我的第一个想法是定义一些结构来接收信息,例如
public static class JuliaComm
{
public struct JuliaObject
{
public string tag { get; set; }
public JuliaType type { get; set; }
public long size { get; set; }
public sbyte data { get; set; }
}
public struct JuliaType
{
public string tag { get; set; }
public List<JuliaType> param { get; set; }
public List<string> name { get; set; }
public JuliaType(string tag, List<JuliaType> param, List<string> name)
{
this.tag = tag;
this.param = param;
this.name = name;
}
}
}
internal sealed class JuliaObjectConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
var type = objectType.GetElementType();
var isarr = objectType.IsArray;
return isarr && (type == typeof(Array) || type == typeof(double) || type == typeof(Complex) || type == typeof(long));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
if (reader.TokenType == JsonToken.StartObject)
{
JObject item = JObject.Load(reader);
if (item["tag"] != null)
{
var tag = item["tag"].ToString();
if (tag == "struct")
{
var type = item["type"].ToObject<JuliaComm.JuliaType>();
var data = item["data"]; // to something else ?
}
else if (tag == "array")
{
var type = item["type"].ToObject<JuliaComm.JuliaType>();
var size = item["size"].ToObject<int[]>();
var arr = Array.CreateInstance(type, size);
if (type["param"] == [])
{
// fill array with byte to type converter ?;
}
}
}
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value.GetType().IsClass)
{
writer.WriteStartObject();
writer.WritePropertyName(value.ToString()); // should be the name of the variable
writer.WritePropertyName("tag");
writer.WriteValue("struct");
writer.WritePropertyName("type");
// serializer.Serialize(writer,); // should be a List<JuliaType> converion of all types in class
writer.WriteValue("data");
// serializer.Serialize(writer,); // should be a something ! not clear yet
writer.WriteEndObject();
}
else if (value.GetType().IsArray)
{
}
}
}
internal sealed class JuliaTypeConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(JuliaComm.JuliaType));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jsonObject = JObject.Load(reader);
var tag = "datatype";
var type = jsonObject["type"].ToObject<JuliaComm.JuliaType>();
var param = jsonObject["params"].ToObject<List<JuliaComm.JuliaType>>();
var name = jsonObject["name"].ToObject<List<string>>();
return new JuliaComm.JuliaType(tag, param, name);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
var jtype = value as JuliaComm.JuliaType;
writer.WriteStartObject();
writer.WritePropertyName("tag");
serializer.Serialize(writer,"datatype");
writer.WritePropertyName("params");
serializer.Serialize(writer, jtype.param);
writer.WritePropertyName("name");
serializer.Serialize(writer, jtype.name);
writer.WriteEndObject();
}
}
但这可能完全不合适(我收到静态错误)。
我知道 julia 和 C# 之间的所有原始类型转换,因此使用文件中的信息来推断 C# 类型不会有问题。
抱歉,这篇文章很长,我只是想尽可能清楚,尽管我肯定忘记了一些东西。