2017-07-19 6 views
1

xmlシリアル化とデシリアライゼーション中にクラスのプロパティを無視する例を探しました。私は3つの異なる方法を見つけて、それらをいつ使うべきかを理解できません。私の特別な関心事は、XmlSerializerの方がよい作品です。 ShouldSerialize...ShouldSerializeXXXとXMLシリアル化のXmlIgnoreAttributeを使用する場合

public class Item 
{ 
    public string Name { get; set; } 

    public bool ShouldSerializeName() 
    { 
     return false; 
    } 
} 
  • NonSerialized属性で始まる

    1. XmlIgnore属性

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

      public class Item 
      { 
          [NonSerialized] 
          public string Name { get; set; } 
      } 
      
    3. stackoverflowmsdnXmlIgnoreAttribtueNonSerializedAttributeの違いについていくつかの説明があり、私は XmlIgnoreAttribtueとするとき ShouldSerializeXXXパターンを使用する際の情報を見つけることができませんでした

    。私は両方をXmlSerializerで試してみて、どちらも期待どおりの作業を見ています。

  • +0

    すべてが標準に準拠している場合は、好みのものを選択してください。 PS ShouldSerializeXXXバージョンはひどいアイデアです、それを使わないでください! – DavidG

    +0

    @DavidG:なぜShouldSerializeXXXを使うのはひどい考えですか? – scher

    +0

    あなたはそれらの余分なすべてのメソッドであなたのモデルを汚染しますが、属性はそうしません。 – DavidG

    答えて

    1

    #1と#2との間の基本的な違いは、それらが異なるものを生成することです。XML Schemasタイプのスキーマからメンバーを除外するには、[XmlIgnore]を使用します。条件付きでメンバーを含める場合は、ShouldSerializeXXX()またはXXXSpecifiedを使用します。 (最後に、オプション#3にthis answer[NonSerialized]に述べたようにXmlSerializerによって無視されます。)

    は#1と#2との違いを確認するには、あなたのタイプのためのスキーマを生成するためにxsd.exeを使用することができます。次のスキーマは、バージョン#1に対して生成及び完全Name部材省略されている:

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

    差が原因XmlSerializerxsd.exe両方を生じる:#2については、次の条件付きName部材を含むが

    <xs:complexType name="Item" /> 
    

    ダイナミックコード分析ではなく、スタティックタイプ分析を実行してください。いずれのツールもShouldSerializeName()のソースコードを逆コンパイルしようとしないため、常にfalseを返すため、ケース#2のNameプロパティは常にスキップされると判断できません。したがって、Nameは、実際には現れないにもかかわらずバージョン#2のスキーマに現れます。その後、Webサービスを作成してWSDLでスキーマを公開する(または単に手動で利用できるようにする)と、Nameのメンバーが1つで、もう1つでは、この2つのタイプの異なるクライアントが生成されます。

    問題のプロパティがnull値ではない値型の場合、さらに複雑になる可能性があります。 Itemの次の3つのバージョンを検討してください。まず、無条件に含まれる値プロパティでバージョン:

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

    Idプロパティを完全に省略した次のスキーマを生成します。

    <xs:complexType name="Item" /> 
    

    そして最後に、条件付きで除外valueプロパティを持つバージョン:

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

    Id条件付きでのみ存在して、次のスキーマを生成します:予想通り

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

    スキーマ#2ですが、予告#1と#3の間に違いがあります。最初は、3番目はminOccurs="0"です。この違いは、デフォルトでnullの値を持つメンバーをスキップするためにXmlSerializerdocumentedであるが、null値のない値のメンバーには類似のロジックがないために発生します。したがって、#1の場合Idプロパティは常にシリアル化されるため、がスキーマに示されます。条件付きシリアル化が有効な場合のみ、minOccurs="0"が生成されます。第三スキーマは、クライアントコードの生成に使用される順番になっている場合、IdSpecifiedプロパティがIdプロパティは、実際に直列化復元中に発生したかどうかを追跡するために、自動生成されたコードに追加されます:への結合の詳細については

    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は静的型分析のみを実行するため、シリアライズされる型はシリアライズされます。例えば。次のようになります。

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

      XmlSerializerでシリアル化できません。

    • [XmlIgnore]XmlSerializerに特異的であるが、ShouldSerializeXXX()Json.NETprotobuf-netを含む他のシリアライザによって使用されます。

    • Visual Studioで条件付きシリアル化プロパティの名前を変更しても、対応するShouldSerializeXXX()メソッド名の名前が自動的に変更されることはありません。

    +1

    詳しい説明はありがとうございます。これは私に完璧な決定指針を与えます。すばらしいです。 – scher