C# XmlSerializer - 处理无效 AllXsd 值的通用自定义适配器(如 java 的 XmlJavaTypeAdapter)
C# XmlSerializer - Generic custom adapter to handle not valid AllXsd value (like java's 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 字段的实体,其中一些实体不止一个,这个解决方案不是很实用。我将不得不在所有这些中实施这一点,如果将来我想改变任何东西,我将不得不在所有这些中再次实施。
我如何声明一个通用的自定义适配器来处理所有 DateTime 类型。在 Java 我可以这样做:
@XmlJavaTypeAdapter(CalendarXmlAdapter.class)
@Column(name = "updateDate")
private Calendar DateUpdated;
并在 CalendarXmlAdapter.class 中指定编组和解组
是否有针对 C# 的类似解决方案System.Xml.Serialization.XmlSerializer?
提前致谢
已编辑
解决方案:
它是@dbc 评论和@steve16351 答案的组合。我使用了 CustomDateTime class(在 ReadXml 中做了一些小改动,但不重要),在 SomeDate 字段的声明中(仍然是 DateTime?类型)我这样使用它
[XmlElement(ElementName = "updateDate", IsNullable = true, Type = typeof(CustomDateTime))]
public DateTime? DateUpdated { get; set; }
转换顺利进行
如果您需要对反序列化进行更多控制,可以使用 IXmlSerializable
。据我所知,虽然您不能全局为 XmlSerializer
提供特定类型的自定义转换器,但您可以编写代理 DateTime
class,如下所示实现 IXmlSerializable
,在我的view 比字符串 属性 和相应的 DateTime 属性 的解决方案更优雅;并且会减少对代码库的破坏。
这是此类解决方案的示例。它还利用隐式运算符来避免在您自己的代码中转换 to/from 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();
}
}
我使用大量可序列化对象反序列化一个 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 字段的实体,其中一些实体不止一个,这个解决方案不是很实用。我将不得不在所有这些中实施这一点,如果将来我想改变任何东西,我将不得不在所有这些中再次实施。 我如何声明一个通用的自定义适配器来处理所有 DateTime 类型。在 Java 我可以这样做:
@XmlJavaTypeAdapter(CalendarXmlAdapter.class)
@Column(name = "updateDate")
private Calendar DateUpdated;
并在 CalendarXmlAdapter.class 中指定编组和解组
是否有针对 C# 的类似解决方案System.Xml.Serialization.XmlSerializer?
提前致谢
已编辑
解决方案: 它是@dbc 评论和@steve16351 答案的组合。我使用了 CustomDateTime class(在 ReadXml 中做了一些小改动,但不重要),在 SomeDate 字段的声明中(仍然是 DateTime?类型)我这样使用它
[XmlElement(ElementName = "updateDate", IsNullable = true, Type = typeof(CustomDateTime))]
public DateTime? DateUpdated { get; set; }
转换顺利进行
如果您需要对反序列化进行更多控制,可以使用 IXmlSerializable
。据我所知,虽然您不能全局为 XmlSerializer
提供特定类型的自定义转换器,但您可以编写代理 DateTime
class,如下所示实现 IXmlSerializable
,在我的view 比字符串 属性 和相应的 DateTime 属性 的解决方案更优雅;并且会减少对代码库的破坏。
这是此类解决方案的示例。它还利用隐式运算符来避免在您自己的代码中转换 to/from 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();
}
}