【问题标题】:Problem deserializing generic List's with C# XmlSerializer使用 C# XmlSerializer 反序列化泛型列表的问题
【发布时间】:2009-11-23 23:55:57
【问题描述】:

我在使用 Microsoft 的 .net XmlSerializer 时遇到了一些难题。我正在尝试将一些 XML 反序列化为一个对象,如果我使用单个对象,这很好,但是当将一个对象放入 List 并尝试对其进行序列化/反序列化时,问题就来了。首先,这里有一个示例 C# windows 控制台程序来说明问题:

http://pastebin.com/m22e6e275

如果类 'Foo' 被序列化为根元素,则一切正常,并且正如预期的那样 - JezNamespace xmlns 应用于根 Foo 元素,并且反序列化可以正常进行。但是,如果我创建一个列表并对其进行序列化,则 XmlSerializer: - 创建 ArrayOfFoo 的根元素 - 将 Foo 元素作为该元素的子元素 - 将 Foo 的每个子项的 xmlns 设置为 JezNamespace 命名空间!

我对前两个没问题,但第三个似乎很疯狂......也许是 XmlSerializer 中的错误?有什么办法可以处理这种行为吗?我不想为 Foo 的每个孩子指定我的命名空间,我只想为 Foo 指定它。如果我这样做,目前,XmlSerializer 不会正确反序列化类 - 它只是跳过设置了 JezNamespace xmlns 的任何 Foo 元素。我必须将所有子元素设置为具有该 xmlns。

我想要的是 XmlSerializer 生成类似的东西:

<ArrayOfFoo>
    <Foo xmlns="http://schemas.datacontract.org/2004/07/JezNamespace">
        <Field1>hello</Field1>
        <Field2>world</Field2>
    </Foo>
    <Foo xmlns="http://schemas.datacontract.org/2004/07/JezNamespace">
        <Field1>aaa</Field1>
        <Field2>bbb</Field2>
    </Foo>
</ArrayOfFoo>

... 然后让 XmlSerializer 能够将其正确反序列化为列表。有什么想法可以让我这样做吗?

【问题讨论】:

    标签: c# serialization


    【解决方案1】:

    您的代码在 Foo 上有两个属性,据我所知,您已将它们放在那里以尝试关联命名空间:

     [XmlRootAttribute(Namespace="http://schemas.datacontract.org/2004/07/JezNamespace",
                       IsNullable=false)]
     [XmlTypeAttribute(AnonymousType=true,
                       Namespace="http://schemas.datacontract.org/2004/07/JezNamespace")]
    

    第一个被忽略,因为在您的场景中 Foo 不是根元素。第二个并没有完全做到你可能认为的那样 - 其中的命名空间是 XSD 类型的命名空间,而不是元素本身的命名空间。

    要指定元素的名称和命名空间,您需要在父类的List&lt;Foo&gt; 属性上使用XmlArrayItemAttribute(哦,您将需要该父类):

    public class FooParent
    {
        [XmlArrayItem(ElementName="Foo",
                      Namespace="http://schemas.datacontract.org/2004/07/JezNamespace")]
        public List<Foo> Foos { get; private set; }
    }
    

    这将产生:

    <FooParent>
      <Foos>
        <Foo xmlns="http://schemas.datacontract.org/2004/07/JezNamespace">
          <Field1>hello</Field1>
          <Field2>world</Field2>
        </Foo>
        ...
    

    或者,如果您根本不想要 Foos 中间元素,您可以将上面代码中的 XmlArrayItem 替换为 XmlElement。在这种情况下,输出 XML 将如下所示:

    <FooParent>
      <Foo xmlns="http://schemas.datacontract.org/2004/07/JezNamespace">
        <Field1>hello</Field1>
        <Field2>world</Field2>
      </Foo>
    

    【讨论】:

    • 嗨,帕维尔,感谢您提供的这些有用的 cmets。正如您所说,唯一的问题是必须声明 FooParent 类。这将需要大量的代码重构,因为在我实际上需要它的项目中(我的程序显然只是一个测试用例),相当于“Foo”是一大组可能需要返回的类在一个列表中。如果没有 FooParent 包装类,我绝对没有办法实现这种效果,而是以某种方式直接序列化/反序列化 List
    • 我不知道有什么好的。最接近的方法是使用 CodeDOM 或 Reflection.Emit 在运行时为您生成这些包装类。
    • 好的,谢谢。令人失望的是 Microsoft 没有在 XmlSerializer 中提供此功能。
    • XmlSerializer 已被半弃用(例如,它存在并将保留,但如果可能,您应该考虑使用更现代的序列化堆栈)。特别是,在 .NET 3.0+ 上,请考虑查看 DataContractSerializer。这有其自身的一系列限制 - 尽管查看您的 XML,您没有属性,只有元素,所以应该没问题 - 但它可以更好地控制序列化的工作方式。
    猜你喜欢
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 2014-07-23
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    相关资源
    最近更新 更多