Десериализация родового подкласса с помощью вспомогательного поля объекта - PullRequest
1 голос
/ 30 сентября 2019

Не уверен, как правильно озаглавить этот вопрос, но здесь есть проблема.

public sealed class ObjectPropertySubclassTest
{
    private sealed class CleverBaseClassConverter : JsonConverter<BaseClass>
    {
        public override bool CanWrite => false;

        public override void WriteJson(JsonWriter writer, BaseClass value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override BaseClass ReadJson(JsonReader reader, Type objectType, BaseClass existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            var token = JToken.ReadFrom(reader);
            if (token["Components"] is JArray)
            {
                var collection=new CollectionClass();
                serializer.Populate(token.CreateReader(), collection);
                return collection;
            }
            else
            {
                if (token["Value"] is JArray)
                {
                    var obj = new SubClass<IEnumerable<BaseClass>>();
                    serializer.Populate(token.CreateReader(), obj);
                    return obj;
                }
                else
                {
                    var obj = new SubClass<object>();
                    serializer.Populate(token.CreateReader(), obj);
                    return obj;
                }
            }
        }
    }

    [JsonConverter(typeof(CleverBaseClassConverter))]
    private abstract class BaseClass
    {
        public object Value { get; set; }
    }

    private class SubClass<T>: BaseClass
    {
        public new T Value
        {
            get => (T) base.Value;
            set => base.Value = value;
        }
    }

    private sealed class CollectionClass : SubClass<IEnumerable<BaseClass>>
    {
        public IEnumerable<BaseClass> Components { get=>Value; set=>Value=value; }
        public bool ShouldSerializeValue() => false;
    }

    [Test]
    public void Test()
    {
        var item=new CollectionClass
        {
            Components=new BaseClass[] {new SubClass<string>{Value="hi"},new SubClass<int>{Value=5},   }
        };
        var json = JsonConvert.SerializeObject(item);

        var copy = JsonConvert.DeserializeObject<CollectionClass>(json);

        //why does copy.components have 4 items (2 doubling up)?
        //why does copy.value have 4 items (2 doubling up) as well?
    }
}

Serializaiton работает как положено, но когда я десериализую json в класс коллекции, он заканчивается 4 элементами вместо 2 (в компонентах). Я делаю что-то в корне неправильно с десериализацией? Кроме того, почему он все еще сериализует «Значение» для класса коллекции

JSON: (У меня есть конвертер json для десериализации правильного подкласса)

{"Components":[{"Value":"hi"},{"Value":5}],"Value":[{"Value":"hi"},{"Value":5}]}

Ответы [ 2 ]

0 голосов
/ 30 сентября 2019

Я разобрался, как заставить это работать и почему это дублировало элементы

private class SubClass<T>: BaseClass
{
    public new T Value
    {
        get => (T) base.Value;
        set => base.Value = value;
    }

    //Added this here in the generic subclass
    public virtual bool ShouldSerializeValue() => true;
}

Затем в подклассе коллекции

private sealed class CollectionClass : SubClass<IEnumerable<BaseClass>>
{
    public IEnumerable<BaseClass> Components { get=>Value; set=>Value=value; }

    //this prevents value to be serialized for this type of class
    public override bool ShouldSerializeValue() => false;
}

Наконец, почему это дублировало это? Поскольку значение было сериализовано, и оно агрегировало «компоненты» после десериализации части значения, после десериализации значения он десериализовал бы копоненты, которые приняли уже десериализованный список значений в качестве базы и добавили компоненты к этой коллекции. таким образом, остановка сериализации значения в случае класса коллекции не будет иметь базового json для «значений» и, следовательно, не будет дублировать его.

0 голосов
/ 30 сентября 2019

Используйте

TypeNameHandling.Auto

вместо

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