Ответ 1
Вы можете сериализовать его как XmlElement
, а не как XmlAttribute
, так как представление слишком сложно для атрибута. Это то, что говорит вам исключение.
Я пытаюсь сериализовать класс, некоторые из элементов данных являются объектами Nullable, вот пример
[XmlAttribute("AccountExpirationDate")]
public Nullable<DateTime> AccountExpirationDate
{
get { return userPrincipal.AccountExpirationDate; }
set { userPrincipal.AccountExpirationDate = value; }
}
Однако во время выполнения я получаю сообщение об ошибке
Невозможно выполнить сериализацию члена AccountExpirationDate типа System.Nullable`1 [System.DateTime]. XmlAttribute/XmlText не может использоваться для кодирования сложных типов.
Однако я проверил и Nullable является SerializableAttribute. Что я делаю не так?
Вы можете сериализовать его как XmlElement
, а не как XmlAttribute
, так как представление слишком сложно для атрибута. Это то, что говорит вам исключение.
Если вы просто хотите, чтобы это сработало, возможно, возможно:
using System;
using System.ComponentModel;
using System.Xml.Serialization;
public class Account
{
// your main property; TODO: your version
[XmlIgnore]
public Nullable<DateTime> AccountExpirationDate {get;set;}
// this is a shim property that we use to provide the serialization
[XmlAttribute("AccountExpirationDate")]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public DateTime AccountExpirationDateSerialized
{
get {return AccountExpirationDate.Value;}
set {AccountExpirationDate = value;}
}
// and here we turn serialization of the value on/off per the value
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeAccountExpirationDateSerialized()
{
return AccountExpirationDate.HasValue;
}
// test it...
static void Main()
{
var ser = new XmlSerializer(typeof(Account));
var obj1 = new Account { AccountExpirationDate = DateTime.Today };
ser.Serialize(Console.Out, obj1);
Console.WriteLine();
var obj2 = new Account { AccountExpirationDate = null};
ser.Serialize(Console.Out, obj2);
}
}
Это будет включать только атрибут, если существует ненулевое значение.
Я использовал что-то подобное много раз.
[XmlIgnore]
public Nullable<DateTime> AccountExpirationDate
{
get { return userPrincipal.AccountExpirationDate; }
set { userPrincipal.AccountExpirationDate = value; }
}
///
/// <summary>Used for Xml Serialization</summary>
///
[XmlAttribute("AccountExpirationDate")]
public string AccountExpirationDateString
{
get
{
return AccountExpirationDate.HasValue
? AccountExpirationDate.Value.ToString("yyyy/MM/dd HH:mm:ss.fff")
: string.Empty;
}
set
{
AccountExpirationDate =
!string.IsNullOrEmpty(value)
? DateTime.ParseExact(value, "yyyy/MM/dd HH:mm:ss.fff")
: null;
}
}
Определите Serializable, который инкапсулирует вашу функциональность.
Вот и пример.
[XmlAttribute("AccountExpirationDate")]
public SerDateTime AccountExpirationDate
{
get { return _SerDateTime ; }
set { _SerDateTime = value; }
}
/// <summary>
/// Serialize DateTime Class (<i>yyyy-mm-dd</i>)
/// </summary>
public class SerDateTime : IXmlSerializable {
/// <summary>
/// Default Constructor when time is not avalaible
/// </summary>
public SerDateTime() { }
/// <summary>
/// Default Constructor when time is avalaible
/// </summary>
/// <param name="pDateTime"></param>
public SerDateTime(DateTime pDateTime) {
DateTimeValue = pDateTime;
}
private DateTime? _DateTimeValue;
/// <summary>
/// Value
/// </summary>
public DateTime? DateTimeValue {
get { return _DateTimeValue; }
set { _DateTimeValue = value; }
}
// Xml Serialization Infrastructure
void IXmlSerializable.WriteXml(XmlWriter writer) {
if (DateTimeValue == null) {
writer.WriteString(String.Empty);
} else {
writer.WriteString(DateTimeValue.Value.ToString("yyyy-MM-dd"));
//writer.WriteString(SerializeObject.SerializeInternal(DateTimeValue.Value));
}
}
void IXmlSerializable.ReadXml(XmlReader reader) {
reader.ReadStartElement();
String ltValue = reader.ReadString();
reader.ReadEndElement();
if (ltValue.Length == 0) {
DateTimeValue = null;
} else {
//Solo se admite yyyyMMdd
//DateTimeValue = (DateTime)SerializeObject.Deserialize(typeof(DateTime), ltValue);
DateTimeValue = new DateTime(Int32.Parse(ltValue.Substring(0, 4)),
Int32.Parse(ltValue.Substring(5, 2)),
Int32.Parse(ltValue.Substring(8, 2)));
}
}
XmlSchema IXmlSerializable.GetSchema() {
return (null);
}
}
#endregion
Я столкнулся с подобной проблемой. У меня было свойство datetime (как XmlAttribute) в классе, который был открыт в службе WCF.
Ниже я столкнулся с решением, которое сработало для меня: 1) Класс XmlSerializer не был сериализован XmlAttribute типа с нулевым значением
[XmlAttribute]
public DateTime? lastUpdatedDate { get; set; }
Exception thrown : Cannot serialize member 'XXX' of type System.Nullable`1.
2) Некоторые сообщения предлагают заменить [XmlAttribute] на [XmlElement (IsNullable = true)]. Но это приведет к сериализации Атрибута как элемента, который абсолютно бесполезен. Однако он отлично работает для XmlElements
3) Некоторые предлагают реализовать интерфейс IXmlSerializable в вашем классе, но это не позволяет вызывать службу WCF из приложения, использующего WCF. Так что это тоже не работает в этом случае.
Решение:
Не помещайте свойство как nullable, вместо этого используйте метод ShouldSerializeXXX(), чтобы установить ограничение.
[XmlAttribute]
public DateTime lastUpdatedDate { get; set; }
public bool ShouldSerializelastUpdatedDate ()
{
return this.lastUpdatedDate != DateTime.MinValue;
// This prevents serializing the field when it has value 1/1/0001 12:00:00 AM
}