C# XmlSerializer - 用于处理无效的 AllXsd 值的通用自定义适配器(如 Java 的 XmlJavaTypeAdapter)



我使用大量可序列化对象反序列化xml。 我已经读到,为了避免在 DateTime 中无效的 AllXsd 值,我必须创建一个帮助程序字符串属性,该属性将输入作为字符串处理并转换它。 即

[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 字段的实体,其中一些不止一个,这个解决方案不是很实用。我将不得不在所有这些中实现这一点,如果将来我想改变任何东西,我将不得不在所有这些中再次这样做。 如何声明通用自定义适配器来处理所有日期时间类型。在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; }

转换顺利进行

如果需要对反序列化进行更多控制,可以使用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();
}
}

最新更新