你如何序列化.Net中的几个可选元素之一?

时间:2011-04-07 12:23:14

标签: c# .net serialization

我有一个包含两个参数的类。一个是以分钟为单位的更新时间,另一个是以秒为单位的相同值:

using System.Xml.Serialization;

[XmlRoot(ElementName="config")]
public class Config
{
    [XmlElement(ElementName = "update_mins")]
    public int Minutes 
    {
        get
        {
            return this.Seconds / 60;
        }
        set
        {
            this.Seconds = value * 60;
        }
    }

    [XmlElement(ElementName = "update_secs")]
    public int Seconds { get; set; }
}

我得到的xml字符串可以包含update_mins或update_secs,但不能同时包含两者。我需要能够使用这个类来反序列化这些字符串,这没问题。我还需要能够将这些类分类并发送它们,但是当我进行serailzation时它包括update_secs和update_mins。像这样:

<config>
  <update_mins>23</update_mins>
  <update_secs>1380</update_secs>
</config>

当我想要这个时:

<config>
  <update_secs>1380</update_secs>
</config>

我尝试将XmlIgnore放在update_mins值上,但这阻止了它反序列化元素。是否可以这样做,如果是这样的话?

我的完整代码示例是:

namespace Scrap
{
    class Program
    {
        static void Main(string[] args)
        {
            string s = "<config><update_mins>23</update_mins></config>";

            XmlSerializer searializer = new XmlSerializer(typeof(Config));
            Config result = (Config)searializer.Deserialize(new StringReader(s));

            Console.WriteLine("Minutes: " + result.Minutes);
            Console.WriteLine("Seconds: " + result.Seconds);

            Debug.Assert(result.Minutes == 23);
            Debug.Assert(result.Seconds == 1380);

            StringWriter s2w = new StringWriter();
            searializer.Serialize(s2w, result);

            Console.WriteLine(s2w.ToString());

            string xmlResult = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n" +
                "<config xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n" +                
                "  <update_secs>1380</update_secs>\r\n" +
                "</config>";

            Debug.Assert(s2w.ToString() == xmlResult);

            Console.ReadKey(true);
        }
    }

    [XmlRoot(ElementName = "config")]
    public class Config
    {
        [XmlElement(ElementName = "update_mins")]        
        public int Minutes
        {            
            get
            {
                return this.Seconds / 60;
            }    
            set
            {
                this.Seconds = value * 60;
            }
        }

        [XmlElement(ElementName = "update_secs")]
        public int Seconds { get; set; }
    }
}

3 个答案:

答案 0 :(得分:0)

我会在[XmlIgnore]上使用Minutes,因为它是

  • 取决于秒数
  • 计算字段
  • 数据传输冗余

修改

您提到您无法控制哪个元素被填充,它可能是其中之一或两者。

一种可能的解决方案是添加一层抽象。

  • 定义内部公共属性,例如SecondsXmlMinutesXml,让他们读取XML值(在其上定义属性)
  • 保留MinutesSeconds
  • 有一个布尔字段_isLoaded
  • 每当访问MinutesSeconds时,请检查_isLoaded,如果为false,则检查SecondsXmlMinutesXml中的值,以确定哪个已加载相应地设置MinutesSeconds

如果您不希望SecondsXmlMinutesXml公开,请将其定义为私有,但使用DataContractSerializer进行反序列化。

答案 1 :(得分:0)

尝试

class Config : IDeserializationCallback
{
    void IDeserializationCallback.OnDeserialization(object sender) 
    {
    }
}

class Config
{
    [OnDeserializing]
    void OnDeserialization(StreamingContext context) 
    {
    }
}

答案 2 :(得分:0)

这仍然不是一个理想的解决方案,但我解决这个问题的方法是将[XmlIgnore]添加到Minutes属性(正如Aliostad和其他人所建议的那样),然后像这样添加AllElements属性:

    [XmlAnyElement]
    public XmlElement[] AllElements
    {
        get
        {
            XmlElement[] value = new XmlElement[0];
            return value;
        }

        set
        {
            if (value != null)
            {
                foreach (XmlElement e in value)
                {
                    switch (e.Name)
                    {
                        case "update_mins":
                            this.Minutes = Convert.ToInt32(e.InnerText);
                            break;
                    }
                }
            }
        }
    }