代码之家  ›  专栏  ›  技术社区  ›  scher

何时使用ShouldSerializeXXX与XmlIgnoreAttribute进行XML序列化

  •  2
  • scher  · 技术社区  · 7 年前

    我寻找了在xml序列化和反序列化期间忽略类属性的示例。我找到了三种不同的方法,但不知道应该在什么时候使用。我特别感兴趣的是,和谁一起工作 XmlSerializer

    1. XmlIgnore 属性

      public class Item
      {
          [XmlIgnore]
          public string Name { get; set; }
      }
      
    2. ShouldSerialize...

      public class Item
      {
          public string Name { get; set; }
      
          public bool ShouldSerializeName()
          {
              return false;
          }
      }
      
    3. NonSerialized 属性

      public class Item
      {
          [NonSerialized]
          public string Name { get; set; }
      }
      

    其中有一些关于 XmlIgnoreAttribtue NonSerializedAttribute 在…上 stackoverflow msdn ,我无法找到有关何时使用的信息 XmlIgnoreAttribtue ShouldSerializeXXX

    1 回复  |  直到 7 年前
        1
  •  3
  •   dbc    7 年前

    #1和#2之间的基本区别在于,它们生成不同的 XML Schemas 。如果希望从类型的架构中排除成员,请使用 [XmlIgnore] 。如果希望有条件地包括成员,请使用 ShouldSerializeXXX() XXXSpecified (最后,如 this answer , [NonSerialized] 在选项中#3被忽略 XmlSerializer

    要查看#1和#2之间的差异,可以使用 xsd.exe 为类型生成模式。以下模式是为版本#1生成的,完全省略了 Name 成员:

    <xs:complexType name="Item" />
    

    名称

    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
    </xs:sequence>
    

    产生差异的原因是 两者都执行 静态类型分析 而不是 动态代码分析 。两种工具都无法确定 在#2的情况下,属性将始终被跳过,因为两个工具都没有尝试反编译的源代码 ShouldSerializeName() false 因此 将出现在版本#2的架构中,尽管在实践中从未出现过。如果随后创建web服务并使用发布模式 WSDL (或者简单地手动提供),将为这两种类型生成不同的客户端——一种没有 名称 成员和一个。

    当所讨论的属性是不可为null的值类型时,可能会产生额外的复杂性。考虑以下三个版本的 Item

    public class Item
    {
        public int Id { get; set; }
    }
    

    使用生成以下架构 Id 始终存在:

      <xs:complexType name="Item">
        <xs:sequence>
          <xs:element minOccurs="1" maxOccurs="1" name="Id" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
    

    public class Item
    {
        [XmlIgnore]
        public int Id { get; set; }
    }
    

    生成以下模式,该模式完全省略了 身份证件 属性:

      <xs:complexType name="Item" />
    

    public class Item
    {
        public int Id { get; set; }
    
        public bool ShouldSerializeId()
        {
            return false;
        }
    }
    

    使用生成以下架构

      <xs:complexType name="Item">
        <xs:sequence>
          <xs:element minOccurs="0" maxOccurs="1" name="Id" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
    

    模式#2与预期的一样,但请注意#1和#3之间有一个区别:第一个有 minOccurs="1" minOccurs="0" .产生差异的原因是 XmlSerializer documented null 默认值,但对于不可为null的值成员没有类似的逻辑。因此 身份证件 案例#1中的属性将始终序列化,因此 在模式中指示。只有在启用条件序列化时 最小值=“0” IdSpecified 属性将添加到自动生成的代码中,以跟踪 身份证件 在反序列化过程中实际遇到了属性:

    public partial class Item {
    
        private int idField;
    
        private bool idFieldSpecified;
    
        /// <remarks/>
        public int Id {
            get {
                return this.idField;
            }
            set {
                this.idField = value;
            }
        }
    
        /// <remarks/>
        [System.Xml.Serialization.XmlIgnoreAttribute()]
        public bool IdSpecified {
            get {
                return this.idFieldSpecified;
            }
            set {
                this.idFieldSpecified = value;
            }
        }
    }
    

    有关绑定到条件序列化值成员的更多详细信息,请参阅 XML Schema Binding Support: MinOccurs Attribute Binding Support ShouldSerialize*() vs *Specified Conditional Serialization Pattern

    这是主要区别,但也有次要区别,可能会影响您的选择:

    • [XmlIgnore] 不能在派生类中重写,但 ShouldSerializeXXX() here 例如。

    • XmlSerializer 因为,例如,它引用了一种类型 lacks a parameterless constructor ,然后用 [XmlIgnore] ShouldSerializeXXX() { return false; } XmlSerializer 仅执行静态类型分析。E、 g.以下内容:

      public class RootObject
      {
          // This member will prevent RootObject from being serialized by XmlSerializer despite the fact that the ShouldSerialize method always returns false.
          // To make RootObject serialize successfully, [XmlIgnore] must be added.
          public NoDefaultConstructor NoDefaultConstructor { get; set; }
      
          public bool ShouldSerializeNoDefaultConstructor() { return false; }
      }
      
      public class NoDefaultConstructor
      {
          public string Name { get; set; }
          public NoDefaultConstructor(string name) { this.Name = name; }
      }
      

      无法由序列化 .

    • 特定于 但是 ShouldSerializeXXX() Json.NET protobuf-net .

    • ShouldSerializeXXX() 方法名称,导致潜在的维护问题。