【问题标题】:Can I provide custom serialization for XmlSerializer without implementing IXmlSerializable?我可以在不实现 IXmlSerializable 的情况下为 XmlSerializer 提供自定义序列化吗?
【发布时间】:2013-06-21 13:42:41
【问题描述】:

我们使用XmlSerializer,我想为某些类提供自定义序列化。但是,我并不总是有能力修改相关类的源代码,否则我可以让它实现IXmlSerializable。有没有办法做到这一点?

【问题讨论】:

  • 我知道您可以使用各种 XmlAttributes(如 XmlElementXmlArray 等)来装饰类,但您是在专门询问如何控制不可修改类的 XML 输出?
  • 我使用“代理”类,它使用给定的根标记名称隐含 IXmlSerializable,并使用 ReadXml 函数构造真正的底层值,然后在公共属性中公开。
  • 好吧,这个constructor overload 可以让你覆盖类型上使用的属性,但我不知道它是否可以让你改变IXmlSerializable.ReadXml 的行为/结果。编辑:您能否将业务对象和第 3 方对象之间的序列化问题分开?
  • @Chris。是的 - 我想控制不可修改类的 Xml 输出。具体来说,不可修改的类不允许默认序列化,因为它们有一些带有私有设置器的属性等。
  • @asawyer。那可以工作。如果我序列化具有类型“问题”类 Y 的属性的 X 类型的顶级对象,我将如何使用 Y 的代理?

标签: c# xml-serialization


【解决方案1】:

下面是代理反序列化助手的一个简单示例:

给定一个我们无法在类级别直接控制序列化的类型:

public sealed class Class //contrived example
{
    public string Property {get;set;}
}

还有我们需要反序列化的xml:

<Class>
  <Property>Value</Property>
</Class>

您可以创建一个代理类型来手动处理目标类型的反序列化过程,如下所示:

[XmlRoot("Class")] // <-- Very important
public sealed class ClassSerializerProxy : IXmlSerializable
{
    public Class ClassValue {get;set;}

    public System.Xml.Schema.XmlSchema GetSchema(){return null;}
    public void WriteXml(System.Xml.XmlWriter writer){}

    public void ReadXml(System.Xml.XmlReader reader)
    {
        var x = XElement.ReadFrom(reader) as XElement;
        this.ClassValue = new Class();
        //again this is a simple contrived example
        this.ClassValue.Property = x.XPathSelectElement("Property").Value;
    }
}

用法是:

void Main()
{
    // get the xml value somehow
    var xdoc= XDocument.Parse(@"<Class><Property>Value</Property></Class>");

    // deserialize the xml into the proxy type
    var proxy = Deserialize<ClassSerializerProxy>(xdoc);

    // read the resulting value
    var value = proxy.ClassValue;
}

public object Deserialize(XDocument xmlDocument, Type DeserializeToType)
{
    XmlSerializer xmlSerializer = new XmlSerializer(DeserializeToType);
    using (XmlReader reader = xmlDocument.CreateReader())
        return xmlSerializer.Deserialize(reader);
}

现在加入一些泛型和扩展方法,我们可以稍微清理调用站点以获得最终(EXCEPT EXCEPTION HANDLING)版本:

用法:

void Main()
{
    var xml = @"<Class><Property>Value</Property></Class>";

    var value = xml.DeserializeWithProxy<ClassSerializerProxy,Class>();

    value.Dump();
}

您的实例类型:

public sealed class Class
{
    public string Property {get;set;}
}

代理类型必须实现的接口

public interface ISerializerProxy<TInstanceType> where TInstanceType : class
{
    TInstanceType Value { get; }
}

示例代理现在实现了新接口

[XmlRoot("Class")]
public sealed class ClassSerializerProxy : IXmlSerializable, ISerializerProxy<Class>
{
    public Class Value {get;set;}

    public System.Xml.Schema.XmlSchema GetSchema(){return null;}
    public void WriteXml(System.Xml.XmlWriter writer){}

    public void ReadXml(System.Xml.XmlReader reader)
    {
        var x = XElement.ReadFrom(reader) as XElement;
        this.Value = new Class();
        this.Value.Property = x.XPathSelectElement("Property").Value;
    }
}

反序列化方法现在是string 的扩展方法,可以与任何代理类型一起使用。

public static class ExtensionMethods
{
    public static TInstanceType DeserializeWithProxy<TProxyType,TInstanceType>(this string xml) 
        where TProxyType : ISerializerProxy<TInstanceType> 
        where TInstanceType : class
    {
        using (XmlReader reader = XDocument.Parse(xml).CreateReader())
        {
            var xmlSerializer = new XmlSerializer(typeof(TProxyType));
            return (xmlSerializer.Deserialize(reader) as ISerializerProxy<TInstanceType>).Value;
        }
    }
}

【讨论】:

  • 如果我有一个大对象树,并且想对整个树使用默认序列化,但对某些叶子使用自定义序列化,有没有办法使用这种方法?如果我可以访问源代码,我可以让这些叶子实现 IXmlSerializable,并将自定义序列化放在那里。但是如果不能修改叶子,是否需要为整个树编写序列化代码?或者我可以以某种方式只针对一小部分问题类吗?
  • @asawyer 这是一个很好的答案!我还选择实现 WriteXml 功能,因为我的真实类本身不是 XML 可序列化的。它由一堆只能通过构造函数设置的只读访问器组成。
  • @natephette 我很高兴能够提供帮助!
  • @asawyer 我很想知道 Rob 所问的是否可以使用此代码。
  • @asawyer 问题在这里:stackoverflow.com/questions/44290214/…
猜你喜欢
  • 2012-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-19
  • 2010-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多