【问题标题】:XmlSerializer serializing sub objectsXmlSerializer 序列化子对象
【发布时间】:2010-11-02 09:30:13
【问题描述】:

下面的怎么序列化

[XmlRoot("response")]
public class MyCollection<T>
{
    [XmlElement("person", Type = typeof(Person))]
    public List<T> entry;
    public int startIndex;
}

其中 T 可以是类,如

public class Person
{
    public string name;
}

进入

<response>
  <startIndex>1</startIndex>
  <entry>
      <person>
         <name>meeee</name>
      </person>
  </entry>
  <entry>
      <person>
         <name>youuu</name>
      </person>
  </entry>
</response>

我一直在玩 [XmlArray]、[XmlArrayItem] 和 [XmlElement],但我似乎无法获得正确的组合。啊啊啊。

更新:

[XmlArray("entry")]
[XmlArrayItem("person", Type = typeof(Person))]
public List<T> entry;

给我

<entry><person></person><person></person></entry>


[XmlElement("person", Type = typeof(Person))]
public List<T> entry;

给我

<person></person><person></person>

【问题讨论】:

  • 泛型仍然会是个问题...封闭类型中的T是什么(只有封闭类型可以序列化)?
  • 我也不确定这与默认值有什么关系——也许是重新命名...真的是关于嵌套子对象吗?
  • 一个开放的泛型类型是 List;一个封闭的泛型类型是 List。不知道T,很难理解List和Person的关系
  • @seanlinmt:如果你仍然感兴趣,我可以通过 XSD.EXE 运行 OpenSocial 模式,并且我已经学会了如何填充和序列化它。

标签: c# .net xml-serialization


【解决方案1】:

我找到了一种不使用 IXmlSerializable 的方法。使用 XmlDictionaryWriter 格式化必要的部分,其余部分只需使用 DataContractSerializer。我为 MyCollection 创建了一个接口

public interface IMyCollection
{
    int getStartIndex();
    IList getEntry();
}

因此,MyCollection 不再使用任何 XMLxxxx 属性进行修饰。转换为字符串的方法如下。可以改进吗?

public string ConvertToXML(object obj)
{
    MemoryStream ms = new MemoryStream();
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(ms, Encoding.UTF8, true))
    {
         writer.WriteStartDocument();
         if (obj is IMyCollection)
         {
              IMyCollection collection = (IMyCollection)obj;
              writer.WriteStartElement("response");
              writer.WriteElementString("startIndex","0");
              var responses = collection.getEntry();
              foreach (var item in responses)
              {
                   writer.WriteStartElement("entry");
                   DataContractSerializer ser = new DataContractSerializer(item.GetType());                
                   ser.WriteObject(writer, item);
                   writer.WriteEndElement();
              }
              writer.WriteEndElement();
        }
        writer.Flush();
        return Encoding.UTF8.GetString(ms.ToArray());
}

【讨论】:

    【解决方案2】:

    这听起来像我遇到的类似问题..我终于破解了它并将所有内容发布在问题here..

    XML Serialization and Inherited Types

    这样有用吗?

    【讨论】:

    • 抱歉标题误导。现在已经修好了。至于排除默认值。我使用公共日期时间?生日{得到;放; } [XmlIgnore] public boolbirthdaySpecified { get { return birthday.HasValue; } }
    • 到目前为止,xxxSpecified 对我来说没问题……但主要问题是子对象的嵌套。
    • 老实说,我不确定我的答案中的代码在哪里让您失望。仅使用 XML 属性,您无法获得开箱即用的干净解决方案,并且作为标记 [正确] 说,在这种情况下,实现 IXmlSerializable 是一种痛苦。基本上,您需要滚动自己的一点序列化来处理“通用”位。您是否查看了我答案中的代码?有什么我可以帮忙澄清的吗?
    • 抱歉,Marc,刚刚意识到我拼错了你的名字。我很抱歉。
    • 我希望我能得到一个开箱即用的干净解决方案。我的意思是我的问题似乎很直接,对吧?所以我认为解决方案应该很直接,而不是拐弯抹角?
    【解决方案3】:

    在不彻底改变类的情况下,我看不到任何明显的方法可以让它输出这些结果......这可能不是你想要的,但通过镜像所需的输出(在 DTO 中并不罕见)它得到了正确的结果...

    否则,您可能正在查看IXmlSerializable,这是一个巨大的痛苦:

    using System;
    using System.Collections.Generic;
    using System.Xml.Serialization;
    [XmlRoot("response")]
    public class MyResponse {
        public MyResponse() {
            Entries = new List<Entry>();
        }
        [XmlElement("startIndex", Order = 1)]
        public int StartIndex { get; set; }
        [XmlElement("entry", Order = 2)]
        public List<Entry> Entries { get; set; }
    }
    public class Entry {
        public Entry() { }
        public Entry(Person person) { Person = person; }
        [XmlElement("person")]
        public Person Person { get; set; }
        public static implicit operator Entry(Person person) {
            return person == null ? null : new Entry(person);
        }
        public static implicit operator Person(Entry entry) {
            return entry == null ? null : entry.Person;
        }
    }
    public class Person {
        [XmlElement("name")]
        public string Name { get; set; }
    }
    static class Program {
        static void Main() {
            MyResponse resp = new MyResponse();
            resp.StartIndex = 1;
            resp.Entries.Add(new Person { Name = "meeee" });
            resp.Entries.Add(new Person { Name = "youuu" });
            XmlSerializer ser = new XmlSerializer(resp.GetType());
            ser.Serialize(Console.Out, resp);
        }
    }
    

    【讨论】:

    • IXmlSerializable 应该比我目前拥有的更好,即。仅通过反射进行序列化和反序列化
    • 我真的不想过多地改变类的结构。我仍然有用于序列化为 JSON 的 DataContract 属性。给出的示例是类的简化版本。我可以同时使用某些 XMLxxx 和 Dataxxx 属性进行装饰,对吗?这样我在序列化为 JSON 或 XML 时可以有不同的格式。
    • 是的,但我不确定如果XmlSerializer 不想按照你想要的方式写东西会有什么帮助...
    • 似乎使用 IXmlSerializable,我将不得不明确指定我想要序列化的每个字段:(
    猜你喜欢
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多