Newtonsoft.json эквивалент XmlChoiceIdentifier - PullRequest
1 голос
/ 17 мая 2019

В настоящее время я работаю над оболочкой API стороннего API XML.Я надеюсь использовать один и тот же объект и конечную точку с веб-API для поддержки обоих.(почти работает)

Проблема возникает при работе со следующими типами объектов:


enum ItemsChoiceType
{
    Foo,
    Bar,
    Baz
}

...
        [XmlElement("Foo", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [XmlElement("Bar", typeof(BarClass), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [XmlElement("Baz", typeof(string), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        [XmlChoiceIdentifier("ItemsElementName")]
        public object[] Items
        {
            get => itemsField;
            set => itemsField = value;
        }

        /// <remarks/>
        [XmlElement("ItemsElementName")]
        [XmlIgnore()]
        public ItemsChoiceType[] ItemsElementName
        {
            get => itemsElementNameField;
            set => itemsElementNameField = value;
        }
...

При использовании объектов массивы выглядят так:

obj.Items = new object[]{"This is Foo", "This is Baz", new BarClass()};
obj.ItemsElementName = new ItemsChoiceType[] {Foo, Baz, Bar};

XML выглядит следующим образом:

<root>
    <Foo>This is Foo</Foo>
    <Baz>This is Baz</Baz>
    <Bar>/*BarClass xml*/</Bar>
</root>

При преобразовании в json два массива отлично сериализуются, но десериализация BarClass не получает правильный тип BarClass, поскольку его десериализация в объект []и является объектом JO.Чтение документации newtonsoft.json было менее чем полезно для решения этой проблемы (хотя я многое узнал о некоторых других вещах).

TypeNameHandling не будет работать из-за проблем безопасности вокруг него.XML работает, потому что Enum определяет тип и имя XML-элемента в Items.

1 Ответ

0 голосов
/ 17 мая 2019

Ну, это не совсем то, что я искал, но я решил это.Я наткнулся на
Сериализационные обратные вызовы , в частности OnDeserialized, где я могу запросить ItemsElementName и посмотреть, существует ли значение перечисления, а затем преобразовать тип.

Это не близкоуниверсальный, на который я надеялся, но он решает проблему для этого конкретного класса.

...

        [OnDeserialized]
        internal void OnDeserializedMethod(StreamingContext context)
        {
            for (int i = 0; i < itemsElementNameField.Length; i++)
            {
                switch (itemsElementNameField[i])
                {
                    case ItemsChoiceType.Bar:
                        switch (Items[i])
                        {
                            case BarClass _:
                                return;
                            case JObject o:
                                Items[i] = new BarClass
                                               {
                                                   /*properties*/
                                               };
                                break;
                        }

                        break;
                        //All the other enum items we care about.
                }
            }
        }

...
...