XmlSerializer.Deserialize为一个子类(不是一个数组)

时间:2013-12-12 05:27:44

标签: c# xml visual-studio-2010 debugging serialization

所以这让我难以忍受了好几个小时......我有一个xml结构,看起来像这样:

<custom>
  <priceLower>999999</priceLower>
  <priceUpper>1000001</priceUpper>
  <investment>true</investment>
  <offtheplan>false</offtheplan>
  <office>
    <name>Melbourne Office</name>
    <officeName>Head Office</officeName>
    ... more elements removed
  </office>
</custom>

在我的应用程序中,我有一个Custom类,它从上面的xml中反序列化,定义如下:

    [Serializable]
public class Custom : BaseEntity, IDataModel
{
    [XmlElement("investment")]
    public string Investment { get; set; }
    [XmlElement("offtheplan")]
    public string Offtheplan { get; set; }
    [XmlElement("priceLower")]
    public Decimal? PriceLower { get; set; }
    [XmlElement("priceUpper")]
    public Decimal? PriceUpper { get; set; }
    [XmlElement("office")]
    public Office Office { get; set; }

我的Office对象定义如下:

    [Serializable]
public class Office : BaseEntity, IDataModel
{
    // temporary for debugging purposes:
    private string _officeName;

    [XmlElement("name")]
    public string Name { get; set; }
    [XmlElement("officeName")] 
    public string OfficeName { get; set; }
    [XmlElement("addressL1")]
    public string Address1 { get; set; }
    ... more fields removed }

Deserialize代码(由辅助类调用,并接收包含A Custom对象的Property Object,其中包含一个Office对象)如下所示:

            XmlSerializer s = null;
    XmlAttributeOverrides attrOverrides = null;

            /// if it's a Residential type, do it this way
            if (typeof(T) == typeof(Residential))
            {
                attrOverrides = new XmlAttributeOverrides();
                var attrs = new XmlAttributes();
                var attr = new XmlElementAttribute();
                attr.ElementName = "office";
                attr.Type = typeof(Office);
                attrs.XmlElements.Add(attr);
                attrOverrides.Add(typeof(Office), "office", attrs);
                s = new XmlSerializer(typeof(T), attrOverrides);
            }

            s = attrOverrides == null 
                ? new XmlSerializer(typeof(T)) 
                : new XmlSerializer(typeof(T), attrOverrides);

            var obj = s.Deserialize(stream);
            return (T)obj;

SO ... Custom对象完全反序列化..没有问题。但是办公室没有 - 所有它的属性总是以空的形式出现。

有没有办法准确指定xml树中哪个元素包含Office对象的数据?我已经尝试将Office对象移动到与Custom(在Property对象上)相同的级别,这实际上更有意义,但这也不起作用 - 我将它移动到Custom下以匹配xml结构,因为我不能改变它,我找不到一种方法来指定从哪里得到它的数据。

我在这里遇到的另一点奇怪......我添加了一个Serializer函数,它基本上从反序列化的对象创建一个新的XML文件。我可以一直调试到调用Serialize函数的位置 - 如果我在对象内部进行序列化之前查看,我可以看到Office对象只包含空值。但序列化程序实际上将数据序列化为我的新XML文件。

这里甚至更奇怪。如果我在调用Serialize()之前查看对象,那么它将始终序列化一个空元素。但是,如果我在序列化发生之前没有查看该对象,它会将数据序列化到那里。我已经多次验证了这一点 - 这绝不是行为。有没有人见过这样的东西?框架是否在我身上耍花招,如果是这样的话,那就是

更新:

只是为了澄清一下,我的XML看起来像这样(我上面只展示了一个施法):

<propertyList>
  <residential>
    <custom>
      <property1>
      <office>
        <officeName>
          Office Name Here
        </officeName>
      </office>
    </custom>
  </residential>
</propertyList>

所以那里有几个级别的嵌套,这可能是我的问题,尽管我认为这更像是一个VS问题。

反序列化器正在处理完整的XML,并反序列化为这样的类结构:

住宅:物业:BasePropertyType

  • 包含自定义对象
  • 包含Office对象

自定义和Office对象都在Residential对象上实例化。我已经尝试将Office对象放在Custom对象上(以匹配xml结构),但这没有任何区别。自定义序列化正确,Office没有。

Visual Studio调试器是否可能是红鲱鱼。正如我之前提到的,如果我调试并查看反序列化对象,它会将其显示为空,然后当我将其序列化回XML时,它会变为空。但是如果我不进行调试而只是在不查看对象的情况下单步执行,则所有属性都会正确地序列化到XML。当我无法调试那里正在发生的事情时,这使我很难继续前进并完成我需要的其余数据处理。有没有人在VS之前看到VS中的行为?

2 个答案:

答案 0 :(得分:0)

关于您的第一个问题,XmlSerializer可以处理简单的层次结构,因此在您的示例中XmlAttributeOverrides不是必需的:

    [Serializable]
    [XmlRoot("custom")]
    public class Custom 
    {
        [XmlElement("investment")]
        public string Investment { get; set; }
        [XmlElement("offtheplan")]
        public string Offtheplan { get; set; }
        [XmlElement("priceLower")]
        public Decimal? PriceLower { get; set; }
        [XmlElement("priceUpper")]
        public Decimal? PriceUpper { get; set; }
        [XmlElement("office")]
        public Office Office { get; set; }
    }

    [Serializable]
    public class Office
    {
        // temporary for debugging purposes:
        private string _officeName;

        [XmlElement("name")]
        public string Name { get; set; }
        [XmlElement("officeName")]
        public string OfficeName { get; set; }
        [XmlElement("addressL1")]
        public string Address1 { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string xml = @"<custom>
  <priceLower>999999</priceLower>
  <priceUpper>1000001</priceUpper>
  <investment>true</investment>
  <offtheplan>false</offtheplan>
  <office>
    <name>Melbourne Office</name>
    <officeName>Head Office</officeName>
  </office>
</custom>";

            XmlSerializer s = new XmlSerializer(typeof(Custom));

            // Works fine without this
            //XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
            //var attrs = new XmlAttributes();
            //var attr = new XmlElementAttribute();
            //attr.ElementName = "office";
            //attr.Type = typeof(Office);
            //attrs.XmlElements.Add(attr);
            //attrOverrides.Add(typeof(Office), "office", attrs);
            //s = new XmlSerializer(typeof(Custom), attrOverrides);

            using (StringReader reader = new StringReader(xml))
            {
                Custom c = (Custom)s.Deserialize(reader);
            }
        }
    }

答案 1 :(得分:0)

啊哈哈哈......我是个傻瓜!如果一个同事和我一起经历这个问题,我们发现了一些非常愚蠢的事情,那就是:

public string ToString()
{
    Name = null;
    OfficeName = null;
    Address1 = null;
    Address2 = null;
    City = null;
    State = null;
    Postcode = null;
    Phone = null;
    Banner = null;
    Logo = null;

    StringBuilder sb = new StringBuilder();
    sb.Append(String.Format("Name:{0} / OfficeName: {1} / Address1: {2} / Address2: {3} / City: {4} / State: {5} / Postcode: {6} / Phone: {7} / Banner: {8} / Logo: {9}",
        Name, OfficeName, Address1, Address2, City, State, Postcode, Phone, Banner, Logo));
    return sb.ToString();
}

所以每当我看一下调试器中的对象时,它就会调用我的ToString()覆盖,然后覆盖所有的值。

我不觉得羞怯。 LOL