【问题标题】:Serialization of generic properties泛型属性的序列化
【发布时间】:2011-06-25 18:40:08
【问题描述】:

有人可以向我解释为什么第一个示例会序列化为 XML,而第二个示例会在尝试将所有类型相互转换时抛出运行时错误?如果我从第二个示例中删除 XmlElement 属性,它将序列化,但 XML 元素名称将是错误的(“Item”而不是为其类型指定的名称)。第一个 sn-p 是使用模式文件从 XSD 工具生成的。

更好的是,有没有办法让它工作?我更喜欢使用向/从对象转换的泛型类型。它使代码更清晰。显式转换对象表明您的设计存在问题。

public partial class OAIPMHtype
{
    private object itemsField;

    [XmlElement( "GetRecord", typeof( GetRecordType ) )]
    [XmlElement( "Identify", typeof( IdentifyType ) )]
    [XmlElement( "ListIdentifiers", typeof( ListIdentifiersType ) )]
    [XmlElement( "ListMetadataFormats", typeof( ListMetadataFormatsType ) )]
    [XmlElement( "ListRecords", typeof( ListRecordsType ) )]
    [XmlElement( "ListSets", typeof( ListSetsType ) )]
    [XmlElement( "error", typeof( OAIPMHerrorType ) )]
    public object Item
    {
        get { return this.itemsField; }
        set { this.itemsField = value; }
    }
}

这不会序列化。

public class OaiPmh<T>
{
    private T itemsField;

    [XmlElement( "GetRecord", typeof( GetRecordType ) )]
    [XmlElement( "Identify", typeof( IdentifyType ) )]
    [XmlElement( "ListIdentifiers", typeof( ListIdentifiersType ) )]
    [XmlElement( "ListMetadataFormats", typeof( ListMetadataFormatsType ) )]
    [XmlElement( "ListRecords", typeof( ListRecordsType ) )]
    [XmlElement( "ListSets", typeof( ListSetsType ) )]
    [XmlElement( "error", typeof( OAIPMHerrorType ) )]
    public T Item
    {
        get { return itemsField; }
        set { itemsField = value; }
    }
}

为了进一步说明,我尝试在创建 XmlSerializer 对象时指定所有额外的类型,但这没有帮助。

这是抛出的异常:

Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'ErrorRequest' to 'GetRecordRequest'
error CS0030: Cannot convert type 'ErrorRequest' to 'ListRecordsRequest'
error CS0030: Cannot convert type 'ErrorRequest' to 'IdentityRequest'
error CS0030: Cannot convert type 'ErrorRequest' to 'ListSetsRequest'
error CS0030: Cannot convert type 'ErrorRequest' to 'ListIdentifiersRequest'
error CS0030: Cannot convert type 'ErrorRequest' to 'ListMetadataFormatsRequest'
error CS0029: Cannot implicitly convert type 'ListSetsRequest' to 'ErrorRequest'
error CS0029: Cannot implicitly convert type 'ListIdentifiersRequest' to 'ErrorRequest'
error CS0029: Cannot implicitly convert type 'ListMetadataFormatsRequest' to 'ErrorRequest'
error CS0029: Cannot implicitly convert type 'GetRecordRequest' to 'ErrorRequest'
error CS0029: Cannot implicitly convert type 'ListRecordsRequest' to 'ErrorRequest'
error CS0029: Cannot implicitly convert type 'IdentityRequest' to 'ErrorRequest

'

泛型类型有点道理,看看在编译时类型是如何被特定的绑定的。但是看看它是如何与对象引用一起工作的,在我看来它也应该与泛型类型一起工作。

【问题讨论】:

  • 它只是另一个包含一些 int/string 属性的类。没什么特别的。
  • 更新:如果您在各个类之间添加隐式转换运算符,这将起作用。臀部疼痛,但会起作用。

标签: c# .net xml generics xml-serialization


【解决方案1】:

您是否查看过“如何序列化泛型类型”问题下的 Generics FAQ 页面?或许能帮到你。

【讨论】:

    【解决方案2】:

    我认为CS0029 compiler error page on MSDN 提供了您正在寻找的信息。

    根据我阅读本文的方式,您的第一个示例有效,因为您的课程中没有发生转换。因为您明确地传递了Object,所以不需要进行转换,也不会引发编译器错误。

    在第二个示例中,直到运行时才知道类型。通过指定多个 XmlElement 属性,编译器认为所有这些类型都必须是可互换的。但是,由于您没有为这些类型提供显式转换,因此编译器担心这两种类型之间的转换可能是缩小转换并引发错误。

    【讨论】:

    • 我同意这是问题所在,但我很困惑为什么 XmlElement 属性适用于对象属性。它们的属性定义了序列化输出中的 Xml 元素。知道如何解决吗?
    • 我怀疑编译器正在为您指定的每个 XmlElement 属性创建一个类,以便在运行时可以以这些不同的形式序列化输入数据。我不确定您是否会找到解决方案,因为要启用类型之间的序列化,编译器需要在编译时了解这两种类型。 ...但我不是 100% 确定。
    • 所有这些类都存在,我只是没有将它们添加到代码 sn-p 中,因为它们非常简单且与示例无关。
    • @MonkeyWrench 你说“我很困惑为什么 XmlElement 属性对对象属性起作用”。它们处理对象属性是因为 .NET 为 Object 类型分配了特定数量的内存。在您的类(即 GetRecordType、IdentifyType 等)之间进行转换时,.NET 转换没有问题,因为它已经知道 Object 的大小(在内存中)以及您的类的大小。在泛型示例中,.NET 直到运行时才知道泛型类型的大小(在内存中),因此编译器需要对每个类进行显式转换才能编译。
    • 从上面继续...这是必要的,因为如果传递给您的第二个示例的泛型类型分配的内存少于您要转换的类型,您将在转换过程中丢失数据。
    【解决方案3】:

    为不同类型设置不同序列化元素的唯一方法是使用objectIXmlSerializable

    不幸的是,XmlSerializer 无法访问非公共属性。因此,通过第二个 public 属性将项目公开为object 允许序列化。不过,我不会在实际情况下使用它:

    [XmlElement("GetRecord", typeof(GetRecordType))]
    [XmlElement("Identify", typeof(IdentifyType))]
    public object ItemSerializer
    {
        get { return this.Item; }
        set { this.Item = (T)value; }
    }
    
    [XmlIgnore]
    public T Item
    //...
    

    【讨论】:

    • 但这正是我想要避免的。在这种情况下,应该不需要使用 iXmlSerializable 或对象属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 2014-12-20
    • 1970-01-01
    相关资源
    最近更新 更多