具有特定结构的潜在嵌套对象的 BSON 数据的(反)序列化

2023-12-27

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# 类型不会有问题。

抱歉,这篇文章很长,我只是想尽可能清楚,尽管我肯定忘记了一些东西。


从 JSON 到 CSV 会扁平化数据结构,如果排除二进制文件,则可确保数据中不存在任何不兼容的二进制结构。这应该通过更改 JSON 映射到 CSV 的方式来揭示 JSON 中任何隐藏的不兼容性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有特定结构的潜在嵌套对象的 BSON 数据的(反)序列化 的相关文章

随机推荐