简体   繁体   English

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

[英]XmlSerializer.Deserialize for a sub class (not an array)

So this has had me stumped for hours... I have an xml structure that looks like this: 因此,这让我感到迷惑了几个小时……我有一个看起来像这样的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>

In my application I have a Custom class, which deserializes from the above xml fine, defined as follows: 在我的应用程序中,我有一个Custom类,该类从上面的xml fine反序列化,定义如下:

    [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; }

And my Office Object defined as follows: 而我的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 }

The Deserialize code (called by a helper class, and receives a Property Object containing A Custom object, which contains an Office object) looks like this: 反序列化代码(由助手类调用,并接收包含一个Custom对象的属性对象,其中Custom对象包含一个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... The Custom object deserializes perfectly.. no issues there. 所以...自定义对象完全反序列化..那里没有问题。 But the office one doesn't - all it's properties always come through as null. 但是办公场所却没有,它的所有属性始终以null表示。

Is there a way to specify exactly which element in the xml tree contains the data for the Office object? 有没有一种方法可以确切地指定xml树中的哪个元素包含Office对象的数据? i've tried moving the Office Object to sit at the same level as Custom (on the Property object) which makes more sense really, but that didn't work either - i moved it to be under Custom to match the xml structure as I can't change that, and i couldn't find a way to specify where it should get it's data from. 我曾尝试将Office对象移动到与Custom(位于Property对象上)相同的位置,这确实更有意义,但是那也不起作用-我将其移动到Custom下以匹配xml结构。不能改变它,我找不到一种方法来指定应该从哪里获取数据。

Another bit of weirdness I've experienced here... I have added a Serializer function, which basically creates a new XML file from the deserialized objects. 我在这里经历过的另一个怪异之处……我添加了一个Serializer函数,该函数基本上从反序列化的对象创建一个新的XML文件。 I can debug all the way through to where the Serialize function is called - and if I peek inside the object getting serialized before it happens, i can see that the Office object contains only null values. 我可以一直调试直到调用Serialize函数的位置-如果在发生序列化的对象之前先对其进行窥视,我可以看到Office对象仅包含空值。 But the serializer actually serializes data into my new XML file. 但是序列化程序实际上将数据序列化到我的新XML文件中。

Here is where it gets even weirder. 这是更奇怪的地方。 If i peek into the object before Serialize() is called, then it will always serialize an empty element. 如果在调用Serialize()之前先查看对象,则它将始终序列化一个空元素。 BUT, if i don't peek inside that object before the serialization happens, it'll serialize data into there. 但是,如果在序列化发生之前我不偷看那个对象,它将把数据序列化到那里。 I have verified this a bunch of times - without fail that is the behaviour. 我已经多次验证了这一点-毫无疑问,这就是行为。 Has anybody ever seen anything like this? 有人看过这样的东西吗? Is the framework playing tricks on me, and if so whY??? 框架在欺骗我吗?

UPDATE: 更新:

Just to clarify, my XML looks something like this (I only showed an exert above): 为了澄清起见,我的XML看起来像这样(上面我只显示了作用):

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

So there's a few levels of nesting there, which i possibly the issue, though I'm thinking it's more of a VS issue. 因此,那里有一些嵌套级别,这可能是我所要解决的问题,尽管我认为这更多的是VS问题。

The deserializer is working on the full XML, and deserialising down to a class structure like this: 反序列化器正在处理完整的XML,并反序列化为这样的类结构:

Residential : Property : BasePropertyType 住宅:属性:BasePropertyType

  • Contains Custom Object 包含自定义对象
  • Contains Office Object 包含Office对象

Both Custom and Office objects are instantiated on the Residential object. 自定义对象和办公室对象都在住宅对象上实例化。 I have tried putting the Office object on the Custom object instead (to match the xml structure) but that made no difference. 我尝试将Office对象放到Custom对象上(以匹配xml结构),但这没什么区别。 Custom serializes correctly, Office does not. 自定义正确序列化,Office不正确。

Is it at all possible that the Visual Studio debugger is the red herring here. Visual Studio调试器是否完全有可能成为此处的红色鲱鱼。 As i mentioned before, if i debug and take a look at the deserialized object, it shows it as empty, and when i then serialize it back to XML it comes through as empty. 如前所述,如果我调试并查看反序列化的对象,它将显示为空,然后将其序列化回XML时,它将作为空。 But if i don't debug and just step over without taking a look at the object, all the properties serialize correctly to the XML. 但是,如果我不调试而只是不看对象就走了,那么所有属性都会正确地序列化为XML。 It's making it kind of difficult to move on and do the rest of the data processing i need to when i can't debug what's going on there. 当我无法调试正在发生的事情时,这将使继续执行我需要进行的其余数据处理工作变得有些困难。 Has anybody seen behaviour in VS like this before?? 以前有人在VS中看到过这种行为吗?

As to your first question, XmlSerializer can handle simple hierarchies so in your example XmlAttributeOverrides are not necessary: 关于第一个问题, 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);
            }
        }
    }

Ahahahaha... I'm such a goof! 啊哈哈哈哈...我真是个蠢货! Had a workmate run through this with me, and we found something really silly that i'd done, namely: 有一个同事陪伴着我,我们发现我做的事情确实很愚蠢,即:

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();
}

So every time i took a look at the object in the debugger, it was calling my ToString() override, which was then nuking all the values. 因此,每次我在调试器中查看对象时,它都在调用我的ToString()覆盖,然后覆盖所有值。

Don't i feel sheepish. 我不觉得很讨厌。 LOL 大声笑

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM