如何:通过接口应用XmlSerialization

本文探讨了如何在.NET中通过实现IXmlSerializable接口解决序列化接口类型的问题,具体介绍了如何序列化和反序列化继承自同一接口的不同类,以及如何在持有泛型接口类型的类中应用自定义XML序列化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是串行化的高级主题。 对于那些不知道XML序列化是什么的人,那么这可能还不适合您。 对于那些这样做的人,您可能会遇到序列化接口的问题,而使用标准XmlSerialization技术根本无法做到这一点。 本文将探讨如何做到这一点,尽管可能会有些长。 让我们解决以下问题:


 public interface IPoint
    {
        double X;
        double Y;
        double DistanceBetween(IPoint point);
    } 
    public class Point2Dimensional : IPoint
    {
        public double X { get; protected set; }
        public double Y { get; protected set; }
        public virtual double DistanceBetween(IPoint point) { ... }
    } 
    public class Point3Dimensional : Point2Dimensional
    {
        public double Z { get; protected set; }
        public override double  DistanceBetween(IPoint point) { ... }
    } 
如果我们现在有一个具有IPoint的类。

    public class PointHolder
    {
        public IPoint Point { get; set; }
    } 
现在,这意味着我们无法使用标准的序列化来反序列化PointHolder类,因为该序列化器还不够聪明,无法确定应反序列化的类型。 但是,可以使用一些自定义序列化手动进行操作。

首先,我们要确保我们的两点都能序列化/反序列化。 因此,我们稍微更改了代码。 我省略了无参数构造函数,显然您需要在其中添加它们。

1)使IPoint接口实现IXmlSerializable


 public interface IPoint : IXmlSerializable
    {
        double X;
        double Y;
        double DistanceBetween(IPoint point);
    } 
2)像这样使Point2Dimensional和Point3Dimensional实现IXmlSerializable接口。 我刚刚完成了2Dimensional类,显然另一个只是将Z添加到要序列化/反序列化的事物列表中。

   public class Point2Dimensional : IPoint
    {
        public double X { get; protected set; }
        public double Y { get; protected set; }
        public virtual double DistanceBetween(IPoint point) { ... } 
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        } 
        public void ReadXml(System.Xml.XmlReader reader)
        {
            this.X = Convert.ToDouble(reader.GetAttribute("X"));
            this.Y = Convert.ToDouble(reader.GetAttribute("Y"));
        } 
        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteAttributeString("X", this.X.ToString());
            writer.WriteAttributeString("Y", this.Y.ToString());
        }
    } 
现在,我们还需要使PointHolder实现IXmlSerializable。 这使用了一些扩展方法,这些方法可以完成我们将在一分钟内看到的艰苦工作。 同样,您也将需要无参数构造函数。

    public class PointHolder : IXmlSerializable
    {
        public IPoint Point { get; set; } 
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        } 
        public void ReadXml(System.Xml.XmlReader reader)
        {
            this.Point = reader.ReadXmlSerializableElement<IPoint>("Point");
        } 
        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.SaveXmlSerialiableElement("Point", this.Point);
        }
    } 
我们在这里所做的基本上是传递一个元素名称,然后保存或分配我们的Point属性。 现在,让我们看一下在静态类中某个地方定义的扩展方法。

public static void SaveXmlSerialiableElement<T>(this XmlWriter writer, String elementName, T element) where T : IXmlSerializable
        {
            writer.WriteStartElement(elementName);
            writer.WriteAttributeString("TYPE", element.GetType().ToString());
            element.WriteXml(writer);
            writer.WriteEndElement();
        } 
这里发生了什么? 好吧,我们用给定的名称编写一个新元素,然后保存该元素的完整类型和名称空间,在元素本身上调用WriteXml,然后编写结束标记。 因此,XML如下所示:

<点>

<Point3Dimensional TYPE =“ TestApp.Point3Dimensional” x =“ 0”,y =“ 0”,z =“ 0”>

</ Point>

不太困难。 阅读是使事情变得有趣的地方。 有几种我不需要的方法,我敢肯定您可以弄清楚。 代码在这里:

     public static void ReadToElement(this XmlReader reader, String element)
        {
            reader.ReadToNextNode();
            while (reader.Name != element)
            {
                reader.ReadToNextNode();
            }
        } 
        public static void ReadToNextNode(this XmlReader reader)
        {
            // Read the current item to throw it away
            reader.Read(); 
            // Keep on reading till we have read all the whitespace
            while (reader.NodeType == XmlNodeType.Whitespace)
            {
                reader.Read();
            }
        } 
但是,真正有用的部分是:

  public static T ReadXmlSerializableElement<T>(this XmlReader reader, String elementName) where T : IXmlSerializable
        {
            reader.ReadToElement(elementName); 
            Type elementType = Type.GetType(reader.GetAttribute("TYPE"));
            T element = (T)Activator.CreateInstance(elementType);
            element.ReadXml(reader);
            return element;
        } 
这是首先确定感兴趣的元素。 然后,我们读出元素的类型并创建它的新实例。 然后,我们可以调用元素上的ReadXml以初始化其所有成员并返回它。

这意味着我们可以在PointHolder上使用XmlSerialization,而不管它存储在Point属性中的IPoint的类型如何。

From: https://bytes.com/topic/net/insights/871260-how-apply-xmlserialization-interface

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值