.NET Core 3.0序列化多态父子数据。

问题描述 投票:1回答:1

我遇到了一个序列化多态数据的问题。

比如说我有以下的类。

    public class ItemBase
    {
        public ItemBase(string itemType)
        {
            ItemType = itemType;
        }

        public string ItemType { get; private set; }
        public List<ItemBase> Children { get; private set; } = new List<ItemBase>();
    }

    public class RootItem : ItemBase
    {
        public RootItem() : base(Models.ItemType.RootItem.Type)
        {
        }
    }

    public class Text : ItemBase
    {
        public Text(string content) : base(Models.ItemType.Text.Type)
        {
            Content = content;
        }

        public string Content { get; private set; }
    }

在一个应用阶段,我有 RootItem 的所有子代。现在,我需要从ASP.NET Core 3.0 API中返回该值,如何才能干净利落地完成这个任务?

我尝试了一个自定义的Json转换器,多态的情况下一切都没问题,但是子代的问题是,数据不是像父代子代那样输出。类似这样的问题。

 private void Serialize(Utf8JsonWriter writer, ItemBase value)
 {
        if (value is Paragraph paragraph)
            JsonSerializer.Serialize(writer, paragraph);

        if (value is Text text)
            JsonSerializer.Serialize(writer, text);
             ....
 }
json asp.net-core serialization polymorphism parent-child
1个回答
0
投票

最后我用了一个自定义的JSON转换器。我希望它能帮助别人。因为父子关系,因为多态对象,我用递归的方式实现了自定义JSON读写。最终结束了这样的事情。

        public override RootItem Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var item = _toDomainParser.ParseFromJson(ref reader);

            return item;
        }

        public override void Write(Utf8JsonWriter writer, RootItem value, JsonSerializerOptions options)
        {
            _toJsonParser.ParseFromRootItem(value, writer);   
        }

This for read purposes.

        public ItemBase ParseFromReader(ref Utf8JsonReader reader, ItemBase parent)
        {
            //in case of start json we will already have start, but in case of deeper items we don't, so read it
            if (reader.TokenType != JsonTokenType.StartObject)
                reader.Read();//TODO delete if it is not use|also in case for deep in array

            var (propName, value) = ReadString(ref reader);

            if (string.IsNullOrEmpty(propName) && string.IsNullOrEmpty(value))
                return parent;

            var item = DefineItem(value, ref reader);

            if (item == null)
                throw new Exception("Cannot parse item from json");

            parent?.Children.Add(item);

            reader.Read(); // read next json object to check whether there are children

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                //handle there children, because the last property are children
                reader.Read(); //this should be start of the array
                ParseFromReader(ref reader, item);

                reader.Read(); //this should be end of the array
            }

            if (reader.TokenType == JsonTokenType.EndObject) // in case this is sibling
            {
                reader.Read();

                if (reader.TokenType == JsonTokenType.EndArray)
                    return item;

                ParseFromReader(ref reader, parent);
            }

            return item;
        }

        private Img GetImg(ref Utf8JsonReader reader)
        {
            var (prop, val) = ReadString(ref reader);
            return new Img(val);
        }

        private (string propertyName, string value) ReadString(ref Utf8JsonReader reader)
        {
            var isRead = reader.Read();//read propertyName
            if (!isRead)
                return (null, null);

            var propertyName = reader.GetString();

            isRead = reader.Read();//read property itself
            if (!isRead)
                return (null, null);

            var value = reader.GetString();

            return (propertyName, value);
        }

这个用于写。

        private void ParseItem(ItemBase item, Utf8JsonWriter writer)
        {
            writer.WriteStartObject();

            if (item is Paragraph paragraph)
                WriteSingleObject(paragraph, writer);

            if (item is Text text)
                WriteSingleObject(text, writer);

            if (item is RootItem rootItem)
                WriteSingleObject(rootItem, writer);

            if (item is NewLine newLine)
                WriteSingleObject(newLine, writer);

            if (item is Link link)
                WriteSingleObject(link, writer);

            if (item is Strong strong)
                WriteSingleObject(strong, writer);

            if (item is NumberList numberList)
                WriteSingleObject(numberList, writer);

            if (item is ListItem listItem)
                WriteSingleObject(listItem, writer);

            if (item is Pre pre)
                WriteSingleObject(pre, writer);

            if (item is Code code)
                WriteSingleObject(code, writer);

            if (item is Figure figure)
                WriteSingleObject(figure, writer);

            if (item is Img img)
                WriteSingleObject(img, writer);

            if (item.Children != null && item.Children.Count > 0)
            {
                writer.WriteStartArray(ItemBase.ChildrenNaming);

                foreach (var child in item.Children)
                    ParseItem(child, writer);

                writer.WriteEndArray();
            }

            writer.WriteEndObject();
© www.soinside.com 2019 - 2024. All rights reserved.