@hax
junior developer

Как десериализовать Nullable типы в атрибуты XML?

Привет. У меня есть такой контракт:

[Serializable]
public class XmlContract
{
     [XmlAttribute("ImportantAttribute")]
     [DefaultValue(null)]
     public decimal? Field { get; set; }
}


Такой контракт не сериализуется в XML формат и не десериализуется из XML из-за наличия Nullable свойства. Находил разные решения на SO типо таких. Нашёл два решения:
1) Создать Nullable Property с атрибутом [XmlIgnore], затем создать уже не-nullable property, которое будет устанавливать через сеттеры и геттеры значения для nullable property.
2) Имплементировать интерфейс IXmlSerializable и в нём описать логику сериалиализации/десериализации nullable типов.

Мне такие решения не совсем подходят (хотя они вроде и работают), потому что у меня в контракте около 100-150 пропертей, для каждого писать такую логику - просто жесть. Заменить [XmlAttribute] на [XmlElement] тоже не получится, ибо контракт вендоров поставляет именно контракт с XML атрибутами.

Очень хочется надеяться, что кто-то уже сталкивался с такой проблемой, ибо вроде кейс не такой уж уникальный. Но я уже потратил много времени в гугле в поисках решения и ничего не нашёл - все тщетно :(
  • Вопрос задан
  • 1055 просмотров
Решения вопроса 1
firedragon
@firedragon
Не джун-мидл-сеньор, а трус-балбес-бывалый.
Посмотрите у меня в гите, там как раз нулевые атрибуты приходят из фиас. Сейчас с мобильного не могу точный кусок скинуть
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@acwartz
Тут должна быть ваша реклама.
Видимо плохо искали, либо искали какие-то готовые решения.
[XmlElement(IsNullable = true)]
или
public int? MyNullable{ get; set; }
    public bool ShouldSerializeMyNullable()
    {
        return true;
    }
Ответ написан
@John_Nash
coder
using System;
    using System.IO;
    using System.Xml.Serialization;

    namespace Serialization
    {
        [Serializable]
        public class Person
        {
            public string Name { get; set; }
            public int? Age { get; set; }
            public Company Company { get; set; }

            public Person()
            { }

            public Person(string name, int? age, Company comp)
            {
                Name = name;
                Age = age;
                Company = comp;
            }
        }

        [Serializable]
        public class Company
        {
            public string Name { get; set; }

            // стандартный конструктор без параметров
            public Company() { }

            public Company(string name)
            {
                Name = name;
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                Person person1 = new Person("Tom", 29, new Company("Microsoft"));
                Person person2 = new Person("Bill", null, new Company("Apple"));
                Person[] people = new Person[] { person1, person2 };

                XmlSerializer formatter = new XmlSerializer(typeof(Person[]));

                using (FileStream fs = new FileStream("people.xml", FileMode.OpenOrCreate))
                {
                    formatter.Serialize(fs, people);
                }

                using (FileStream fs = new FileStream("people.xml", FileMode.OpenOrCreate))
                {
                    Person[] newpeople = (Person[])formatter.Deserialize(fs);

                    foreach (Person p in newpeople)
                    {
                        Console.WriteLine($"Имя: {p.Name} --- Возраст: {p.Age?.ToString() ?? "NULL"} --- Компания: {p.Company.Name}");
                    }
                }
                Console.ReadLine();
            }
        }
    }


Если какая-то специфичная схема, воспользуйтесь утилитой xsd. Она должна использовать все возможности XmlSerializer.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы