C # XmlSerializer - универсальный настраиваемый адаптер для обработки недопустимого значения AllXsd (например, XmlJavaTypeAdapter в java) - PullRequest
0 голосов
/ 08 октября 2018

Я десериализирую xml, используя множество сериализуемых объектов.Я читал, что во избежание недопустимого значения AllXsd в DateTime, мне нужно создать вспомогательное свойство строки, которое будет обрабатывать ввод как строку и преобразовывать ее.т.е.

[XmlIgnore]
public DateTime? DateUpdated { get; set; }

[XmlElement("updateDate")]
public string DateUpdatedAsText
{
    set
    {
        if (!string.IsNullOrWhiteSpace(value))
        {
            try
            {
                DateUpdated = DateTime.Parse(value, CultureInfo.InvariantCulture);
            }
            catch (Exception) { }
        }
    }
    get
    {
        return DateUpdated.HasValue ? DateUpdated.Value.ToString("yyyy-MM-ddTHH:mm:ss") : null;
    }
}

Это проверено и прекрасно работает.Однако ...

У меня есть более 100 сущностей, которые содержат поля DateTime, некоторые из них более одного, и это решение не очень практично.Я должен буду реализовать это во всех из них, и если я хочу что-то изменить в будущем, мне придется сделать это снова во всех из них.Как я могу объявить общий пользовательский адаптер для обработки всех типов DateTime.В Java я могу сделать это:

@XmlJavaTypeAdapter(CalendarXmlAdapter.class)
@Column(name = "updateDate")
private Calendar DateUpdated;

и в CalendarXmlAdapter.class указать маршалинг и демаршаллинг

Есть ли подобное решение для C # System.Xml.Serialization.XmlSerializer?

Заранее спасибо

РЕДАКТИРОВАНИЕ

РЕШЕНИЕ: Это комбинация комментария @dbc и ответа @ steve16351.Я использовал класс CustomDateTime (с некоторыми незначительными изменениями в ReadXml, но это не важно) и в объявлении поля SomeDate (которое осталось типом DateTime?) Я использовал его следующим образом:

    [XmlElement(ElementName = "updateDate", IsNullable = true, Type = typeof(CustomDateTime))]
    public DateTime? DateUpdated { get; set; }

Преобразование происходитгладко

1 Ответ

0 голосов
/ 08 октября 2018

Вы можете использовать IXmlSerializable, если вам нужен больший контроль над десериализацией.Несмотря на то, что вы не можете глобально предоставить пользовательские конвертеры для определенных типов в XmlSerializer, насколько мне известно, вы можете написать прокси DateTime класс, как показано ниже, реализующий IXmlSerializable, что, на мой взгляд, более элегантно, чем решение, которое у вас естьстроковое свойство и соответствующее свойство DateTime;и будет меньше нарушать кодовую базу.

Вот пример такого решения.Он также использует неявные операторы, чтобы избежать необходимости преобразования в / из DateTime? в вашем собственном коде.

class Program
{
    static void Main(string[] args)
    {
        XmlSerializer s = new XmlSerializer(typeof(MyClass));
        MyClass myClass = null;
        using (var sr = new StringReader(@"<myXml><updateDate>20181008</updateDate><someProp>Hello, world</someProp></myXml>"))            
            myClass = s.Deserialize(sr) as MyClass;            

        DateTime? myValue = myClass.SomeDate;
        Console.WriteLine($"{myClass.SomeDate}");
        Console.ReadKey();
    }
}

[XmlRoot("myXml")]
public class MyClass
{
    [XmlElement("updateDate")]
    public CustomDateTime SomeDate { get; set; }
    [XmlElement("someProp")]
    public string SomeProp { get; set; }

}

public class CustomDateTime : IXmlSerializable
{
    public DateTime? _dateTime { get; set; }
    private const string EXPECTED_FORMAT = "yyyyMMdd";

    public XmlSchema GetSchema()
    {
        throw new NotImplementedException();
    }

    public void ReadXml(XmlReader reader)
    {
        var elementContent = reader.ReadElementContentAsString();
        _dateTime = String.IsNullOrWhiteSpace(elementContent) ? (DateTime?)null : DateTime.ParseExact(elementContent, EXPECTED_FORMAT, CultureInfo.InvariantCulture);
    }

    public void WriteXml(XmlWriter writer)
    {
        if (!_dateTime.HasValue) return;
        writer.WriteString(_dateTime.Value.ToString(EXPECTED_FORMAT));
    }

    public static implicit operator DateTime? (CustomDateTime input)
    {
        return input._dateTime;
    }

    public static implicit operator CustomDateTime (DateTime input)
    {
        return new CustomDateTime() { _dateTime = input };
    }

    public override string ToString()
    {
        if (_dateTime == null) return null;
        return _dateTime.Value.ToString();
    }
}
...