Как сделать тип значения 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