C#XmlSerializer-处理无效AllXsd值的通用自定义适配器(如java';s XmlJavaTypeAdapter)

C#XmlSerializer-处理无效AllXsd值的通用自定义适配器(如java';s XmlJavaTypeAdapter),c#,xml,datetime,adapter,xmlserializer,C#,Xml,Datetime,Adapter,Xmlserializer,我使用大量可序列化对象反序列化xml。 我已经读到,为了避免DateTime中的AllXsd值无效,我必须创建一个helper字符串属性,该属性将作为字符串处理输入并将其转换。 i、 e 这是经过测试的,效果很好。然而 我有100多个实体,其中包含DateTime字段,其中一些实体不止一个,而且这个解决方案不是很实用。我必须在他们所有人身上实现这一点,如果我想在将来改变什么,我必须在他们所有人身上再做一次。 如何声明通用自定义适配器来处理所有日期时间类型。在Java中,我可以做到这一点: @Xm

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

这是经过测试的,效果很好。然而

我有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属性的解决方案更优雅;而且会更少地破坏代码库

下面是这样一个解决方案的示例。它还利用隐式运算符来避免在您自己的代码中转换为日期时间?

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();
    }
}
类程序
{
静态void Main(字符串[]参数)
{
XmlSerializer s=新的XmlSerializer(typeof(MyClass));
MyClass MyClass=null;
使用(var sr=newstringreader(@“20181008Hello,world”))
myClass=s。反序列化(sr)为myClass;
DateTime?myValue=myClass.SomeDate;
WriteLine($“{myClass.SomeDate}”);
Console.ReadKey();
}
}
[XmlRoot(“myXml”)]
公共类MyClass
{
[XmlElement(“updateDate”)]
公共CustomDateTime SomeDate{get;set;}
[xmlement(“someProp”)]
公共字符串SomeProp{get;set;}
}
公共类CustomDateTime:IXmlSerializable
{
公共日期时间?\u日期时间{get;set;}
应为私有常量字符串\u FORMAT=“yyyyymmdd”;
公共XmlSchema GetSchema()
{
抛出新的NotImplementedException();
}
公共void ReadXml(XmlReader)
{
var elementContent=reader.ReadElementContentAsString();
_dateTime=String.IsNullOrWhiteSpace(elementContent)?(dateTime?)null:dateTime.ParseExact(elementContent,应为_格式,CultureInfo.InvariantCulture);
}
public void WriteXml(XmlWriter)
{
如果(!\u dateTime.HasValue)返回;
writer.WriteString(_dateTime.Value.ToString(应为_格式));
}
公共静态隐式运算符DateTime?(CustomDateTime输入)
{
返回输入。\u dateTime;
}
公共静态隐式运算符CustomDateTime(DateTime输入)
{
返回新的CustomDateTime(){u dateTime=input};
}
公共重写字符串ToString()
{
if(_dateTime==null)返回null;
返回_dateTime.Value.ToString();
}
}

XmlSerializer
实际上不支持代理注入。您可以得到的最接近的技巧是来自的整洁技巧——但不幸的是,这不适用于原语,
DateTime
是一个原语。看,这是失败的。奇怪的是,
DateTime?
(可为空的DateTime)在某些.Net版本上被视为原语,但在其他版本上却不是!在这里,您可以看到在.Net core:上工作而在.Net 4.5上失败的诀窍:。我将颜色结构的注释组合到@steve16351 answer中,结果就是这样!我编辑了我的帖子以提供综合答案。多谢各位!这是一个很好的建议。我对您的代码做了一些更改,并编辑了我的帖子,以提供完整的解决方法。非常感谢你
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();
    }
}