Сериализация / десериализация иерархии классов с помощью .NET Core System.Text.Json - PullRequest
1 голос
/ 03 октября 2019

У меня есть простая иерархия классов, которую я хочу сериализовать, используя System.Text.Json.

Есть 3 класса. База Shape. Унаследованные: Box и Circle.

Я планирую использовать эти классы в качестве тегового объединения в моем приложении внешнего интерфейса, поэтому я только что ввел свойство дискриминатора Tag.

Я написал преобразователь типов, который поддерживает сериализацию / десериализацию этой иерархии.

То, что я пытаюсь понять - это лучший подход для реализации такой функциональности или нет. На самом деле результат сериализации довольно уродлив (я добавил комментарий в пример ниже). Я не уверен, что все сделано лучше, так или иначе, это просто работает.

Вот пример того, как я реализовал сериализацию / десериализацию:

using System;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Serialization.Theory
{
    public abstract class Shape
    {
        public abstract String Tag { get; }
    }

    public class Box : Shape
    {
        public override String Tag { get; } = nameof(Box);

        public Single Width { get; set; }

        public Single Height { get; set; }

        public override String ToString()
        {
            return $"{Tag}: Width={Width}, Height={Height}";
        }
    }

    public class Circle : Shape
    {
        public override String Tag { get; } = nameof(Circle);

        public Single Radius { get; set; }

        public override String ToString()
        {
            return $"{Tag}: Radius={Radius}";
        }
    }

    public class ShapeConverter : JsonConverter<Shape>
    {
        public override Boolean CanConvert(Type typeToConvert)
        {
            return typeToConvert == typeof(Circle) || typeToConvert == typeof(Shape);
        }

        public override Shape Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var raw = reader.GetString();
            var doc = JsonDocument.Parse(raw);
            var prop = doc.RootElement.EnumerateObject().Where(x => x.Name == "Tag").First();
            var value = prop.Value.GetString();

            switch (value)
            {
                case nameof(Circle): 
                    return JsonSerializer.Deserialize<Circle>(raw);
                case nameof(Box):
                    return JsonSerializer.Deserialize<Box>(raw);
                default:
                    throw new NotSupportedException();
            }
        }

        public override void Write(Utf8JsonWriter writer, Shape value, JsonSerializerOptions options)
        {
            if (value is Circle circle)
            {
                writer.WriteStringValue(JsonSerializer.SerializeToUtf8Bytes(circle));
            }
            else if (value is Box box)
            {
                writer.WriteStringValue(JsonSerializer.SerializeToUtf8Bytes(box));
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Keep in base class references like it's a property on another object.
            Shape origin1 = new Box { Width = 10, Height = 20 };
            Shape origin2 = new Circle { Radius = 30 };

            var settings = new JsonSerializerOptions();
            settings.Converters.Add(new ShapeConverter());

            var raw1 = JsonSerializer.Serialize(origin1, settings);
            var raw2 = JsonSerializer.Serialize(origin2, settings);

            Console.WriteLine(raw1); // "{\u0022Tag\u0022:\u0022Box\u0022,\u0022Width\u0022:10,\u0022Height\u0022:20}"
            Console.WriteLine(raw2); // "{\u0022Tag\u0022:\u0022Circle\u0022,\u0022Radius\u0022:30}"

            var restored1 = JsonSerializer.Deserialize<Shape>(raw1, settings);
            var restored2 = JsonSerializer.Deserialize<Shape>(raw2, settings);

            Console.WriteLine(restored1); // Box: Width=10, Height=20
            Console.WriteLine(restored2); // Circle: Radius=30
        }
    }
}

1 Ответ

0 голосов
/ 29 октября 2019

Мне тоже нужен ответ на этот вопрос. Кажется, что другая статья обсуждает это, но не дает хорошего ответа. Смотрите это обсуждение тоже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...