web-dev-qa-db-ja.com

.NET XmlSerializerで値の型をnullにできるようにする方法は?

このオブジェクトがあるとしましょう:

[Serializable]
public class MyClass
{
    public int Age { get; set; }
    public int MyClassB { get; set; }
}
[Serializable]
public class MyClassB
{
    public int RandomNumber { get; set; }
}

XmlSerializerは、次のようにオブジェクトをシリアル化します。

<MyClass>
    <Age>0</age>
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>

プロパティAgeをnullにできるようにするにはどうすればよいですか? IE:プロパティAgeが0未満のときにシリアル化しないようにするには?

私はNullableで試しましたが、それは私のように私のオブジェクトをシリアル化します:

<MyClass>
    <Age d5p1:nil="true" />
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>    

MSDNのドキュメントを読むと、次のことがわかりました。

値型にはnullNothingnullptrnull参照(Visual BasicではNothing)を含めることができないため、IsNullableプロパティを値型として型指定されたメンバーに適用することはできません。さらに、null許容値型の場合、このプロパティをfalseに設定することはできません。このような型がnullNothingnullptrnull参照(Visual BasicではNothing)の場合、xsi:nilをtrueに設定することでシリアル化されます。

ソース: http://msdn.Microsoft.com/en-us/library/system.xml.serialization.xmlelementattribute.isnullable.aspx

値の型をnullに設定できないことを理解しています。 valuetypeは常に何かに設定されます。シリアル化では、現在の値に基づいてシリアル化するかどうかを決定できません。

私は属性で試しましたが、うまくいきませんでした。 agecontainerオブジェクトを作成して、属性を使用してシリアル化を操作しようとしましたが、うまくいきませんでした。

私が本当に欲しいのは:

<MyClass>
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>

プロパティAgeが0(ゼロ)未満の場合。


カスタムのシリアル化を実装する必要があるようです。

ええ、私もそうですが、それなしで逃げたいです。

アプリケーションでは、オブジェクトははるかに複雑であり、シリアル化を自分で処理したくありません。

28
Jean-Francois

私はこれを発見しました。 XmlSerialierXXXSpecifiedブール型プロパティを探して、それを含めるかどうかを決定します。これは問題をうまく解決するはずです。

[Serializable]
public class MyClass
{
  public int Age { get; set; }
  [XmlIgnore]
  public bool AgeSpecified { get { return Age >= 0; } }
  public int MyClassB { get; set; }
}

[Serializable]
public class MyClassB
{
  public int RandomNumber { get; set; }
}

証明:

static string Serialize<T>(T obj)
{
  var serializer = new XmlSerializer(typeof(T));
  var builder = new StringBuilder();
  using (var writer = new StringWriter(builder))
  {
    serializer.Serialize(writer, obj);
    return builder.ToString();
  }
}

static void Main(string[] args)
{
  var withoutAge = new MyClass() { Age = -1 };
  var withAge = new MyClass() { Age = 20 };

  Serialize(withoutAge); // = <MyClass><MyClassB>0</MyClassB></MyClass>
  Serialize(withAge); // = <MyClass><Age>20</Age><MyClassB>0</MyClassB></MyClass>
}

編集:はい、それは文書化された機能です。 MSDNエントリXmlSerializer を参照してください

別のオプションは、特別なパターンを使用して、XmlSerializerによって認識されるブール型フィールドを作成し、XmlIgnoreAttributeをフィールドに適用することです。パターンは、propertyNameSpecifiedの形式で作成されます。たとえば、「MyFirstName」という名前のフィールドがある場合、「MyFirstName」という名前のXML要素を生成するかどうかをXmlSerializerに指示する「MyFirstNameSpecified」という名前のフィールドも作成します。

55
Samuel

Samuelの回答とGreg Beechのコメントをブールプロパティの場合に拡張します。プロパティがbool型の場合、propertySpecifiedプロパティで簡単なテストを作成することはできません。

解決策はNullable <bool>型を使用することであり、propertySpecifiedプロパティのテストは単にproperty.HasValueです。例えば.

using System.Xml.Serialization;

public class Person
{
    public bool? Employed { get; set; }

    [XmlIgnore]
    public bool EmployedSpecified { get { return Employed.HasValue; } }
}

数値プロパティにnull許容型を使用する代わりに(Greg Beechが推奨)、次のようにvalueプロパティを-1などの無効なデフォルト値に設定します。

using System.ComponentModel;
using System.Xml.Serialization;

public class Person
{
    [DefaultValue(-1)]
    public int Age { get; set; }

    [XmlIgnore]
    public bool AgeSpecified { get { return Age >= 0; } }
}
13
jumpalongjim

XmlElementAttribute.IsNullableを使用できます。

[Serializable]
public class MyClass
{
    [XmlElement(IsNullable = true)]
    public int? Age { get; set; }

    public int MyClassB { get; set; }
}
5
Yochai Timmer

これはエイジをintにするのに役立ちますか?そして..

public bool ShouldSerializeAge() { return Age.HasValue; }

..それは、クラスにShouldSerializeXXXメソッドを追加することを意味します!

2
Dog Ears

Nullableについて忘れてください... ShouldSerializeXXXはかなりの解決策です。ここで年齢はあなたの状態に基づいてシリアル化されます。

[Serializable]
public class MyClass
{
    public int Age { get; set; }
    public int MyClassB { get; set; }

    #region Conditional Serialization
    public bool ShouldSerializeAge() { return age > 0; }
    #endregion
}

[Serializable]
public class MyClassB
{
    public int RandomNumber { get; set; }
}
0
hoang

要素の「minoccurs」属性を「minoccurs = "0"」に設定した場合、xsd.exeはXXXSpecifiedプロパティとアクセサーを自動生成します。スキーマを使用してxml /クラスを定義している場合

0
JustAsItSounds