Как сделать тип значения nullable с помощью .NET XmlSerializer?

Предположим, что у меня есть этот объект:

[Serializable]
public class MyClass
{
    public int Age { get; set; }
    public int MyClassB { get; set; }
}
[Serializable]
public class MyClassB
{
    public int RandomNumber { get; set; }
}

XmlSerializer сериализует объект следующим образом:

<MyClass>
    <Age>0</age>
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>

Как я могу присвоить свойство Age nullable? IE: не сериализовать свойство Age, когда оно находится под 0?

Я попытался с Nullable, но он сериализовал мой объект следующим образом:

<MyClass>
    <Age d5p1:nil="true" />
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>    

Прочитав документацию MSDN, я нашел следующее:

Вы не можете применить свойство IsNullable к члену, введенному как тип значения, потому что тип значения не может содержать нулевую ссылку nullNothingnullptra (Nothing в Visual Basic). Кроме того, вы не можете установить для этого свойства значение false для типов значений с нулевым значением. Когда такие типы имеют нулевую ссылку nullNothingnullptra (Nothing в Visual Basic), они будут сериализованы, установив xsi: nil в true.

источник: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlelementattribute.isnullable.aspx

Я понимаю, что тип значения не может иметь значение null. Тип valuetype всегда настроен на что-то. Сериализация не может принять решение о ее сериализации или нет на основе текущего значения.

Я пробовал с атрибутами, но это не сработало. Я попытался создать объект agecontainer и манипулировать его сериализацией с помощью атрибутов, но это не сработало.

Я действительно хочу:

<MyClass>
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>

Когда свойство Age меньше 0 (ноль).


Похоже, вам придётся реализовать пользовательскую сериализацию.

Да, это то, что я тоже, но я бы хотел уйти без него.

В приложении объект намного сложнее, и я не хочу сам обрабатывать сериализацию.

Ответ 1

Я только что открыл это. XmlSerialier ищет свойство XXXSpecified boolean, чтобы определить, должно ли оно быть включено. Это должно решить проблему красиво.

[Serializable]
public class MyClass
{
  public int Age { get; set; }
  [XmlIgnore]
  public bool AgeSpecified { get { return Age >= 0; } }
  public int MyClassB { get; set; }
}

[Serializable]
public class MyClassB
{
  public int RandomNumber { get; set; }
}

Доказательство:

static string Serialize<T>(T obj)
{
  var serializer = new XmlSerializer(typeof(T));
  var builder = new StringBuilder();
  using (var writer = new StringWriter(builder))
  {
    serializer.Serialize(writer, obj);
    return builder.ToString();
  }
}

static void Main(string[] args)
{
  var withoutAge = new MyClass() { Age = -1 };
  var withAge = new MyClass() { Age = 20 };

  Serialize(withoutAge); // = <MyClass><MyClassB>0</MyClassB></MyClass>
  Serialize(withAge); // = <MyClass><Age>20</Age><MyClassB>0</MyClassB></MyClass>
}

Изменить. Да, это документальная функция. См. Запись MSDN для XmlSerializer

Другой вариант - использовать специальный шаблон для создания логического поля, распознаваемого XmlSerializer, и применить XmlIgnoreAttribute к полю. Шаблон создается в виде свойстваNameSpecified. Например, если есть поле с именем "MyFirstName", вы также создадите поле с именем "MyFirstNameSpecified", которое инструктирует XmlSerializer о том, следует ли генерировать элемент XML с именем "MyFirstName".

Ответ 2

Расширение ответа Samuel и комментарий Greg Beech к случаю логического свойства: если свойство имеет тип bool, вы не можете написать простой тест в свойстве propertySpecified.

Решение состоит в использовании Nullable <bool> type, то тест в свойстве свойствоSpecified является просто property.HasValue. например.

using System.Xml.Serialization;

public class Person
{
    public bool? Employed { get; set; }

    [XmlIgnore]
    public bool EmployedSpecified { get { return Employed.HasValue; } }
}

Альтернативой использованию типа с нулевым значением для числового свойства (предложенным Грегом Биком) является установка значения свойства с недопустимым значением по умолчанию, например -1, следующим образом:

using System.ComponentModel;
using System.Xml.Serialization;

public class Person
{
    [DefaultValue(-1)]
    public int Age { get; set; }

    [XmlIgnore]
    public bool AgeSpecified { get { return Age >= 0; } }
}

Ответ 3

Вы можете использовать XmlElementAttribute.IsNullable:

[Serializable]
public class MyClass
{
    [XmlElement(IsNullable = true)]
    public int? Age { get; set; }

    public int MyClassB { get; set; }
}

Ответ 4

Это должно помочь Сделать Age int? и..

public bool ShouldSerializeAge() { return Age.HasValue; }

.. это означает добавление методов ShouldSerializeXXX в ваш класс!

Ответ 5

Забудьте о Nullable... ShouldSerializeXXX - довольно приятное решение. Здесь возраст будет сериализован по вашему состоянию.

[Serializable]
public class MyClass
{
    public int Age { get; set; }
    public int MyClassB { get; set; }

    #region Conditional Serialization
    public bool ShouldSerializeAge() { return age > 0; }
    #endregion
}

[Serializable]
public class MyClassB
{
    public int RandomNumber { get; set; }
}

Ответ 6

xsd.exe будет автогенерировать свойство XXXSpecified и accessors, если вы установите атрибут minoccurs как "minoccurs =" 0 "для элемента... если вы используете схему для определения вашего xml/class