null可能なintをシリアル化する


92

null可能なintを持つクラスがありますか?xml要素としてシリアル化するように設定されたデータ型。値がnullの場合にXMLシリアライザーが要素をシリアル化しないように設定する方法はありますか?

[System.Xml.Serialization.XmlElement(IsNullable = false)]属性を追加しようとしましたが、「IsNullableが 'falseに設定されていない可能性があるため、タイプを反映するエラーがあったことを示すランタイムシリアル化例外が発生します。 'Nullableタイプの場合。'System.Int32'タイプを使用するか、XmlElement属性からIsNullableプロパティを削除することを検討してください。

[Serializable]
[System.Xml.Serialization.XmlRoot("Score", Namespace = "http://mycomp.com/test/score/v1")]
public class Score
{
    private int? iID_m;
    ...

    /// <summary>
    /// 
    /// </summary>        
    public int? ID 
    { 
        get 
        { 
            return iID_m; 
        } 
        set 
        { 
            iID_m = value; 
        } 
    }
     ...
}

上記のクラスは次のようにシリアル化されます:

<Score xmlns="http://mycomp.com/test/score/v1">
    <ID xsi:nil="true" />
</Score>

しかし、nullのIDの場合、ID要素はまったく必要ありません。これは、主にMSSQLでOPENXMLを使用すると、次のような要素に対してnullの代わりに0が返されるためです。

回答:


149

XmlSerializerはShouldSerialize{Foo}()パターンをサポートしているため、メソッドを追加できます。

public bool ShouldSerializeID() {return ID.HasValue;}

{Foo}Specifiedパターンもあります-XmlSerializerがそれをサポートしているかどうかは不明です。


8
XmlSerializerは、[Foo} Specifiedパターンもサポートしています。
デビッドシュミット

23
関連するページはこちら:msdn.microsoft.com/en-us/library/53b8022e%28VS.71%29.aspx
cbp

1
自動生成されたプロパティでShouldSerialize <prop>を使用する方法はありますか?つまり、ローカル変数はありません。
ジェイ

1
@ジェイ:いらない。あなただけHasValueのプロパティを呼び出すことができます。
Steven Sudit、

1
@マークメンバー(プロパティ/フィールド)のために、場合Fooあなたも持っているpublic bool FooSpecified {get {...} set {...}}、そしてgetかどうかを確認するために使用されているFooシリアル化する必要がある、とsetに値を割り当てるときに呼び出されFoo、逆シリアル化中に。
Marc Gravell

26

私はこのマイクロパターンを使用してNullableシリアル化を実装しています:

[XmlIgnore]
public double? SomeValue { get; set; }

[XmlAttribute("SomeValue")] // or [XmlElement("SomeValue")]
[EditorBrowsable(EditorBrowsableState.Never)]
public double XmlSomeValue { get { return SomeValue.Value; } set { SomeValue= value; } }  
[EditorBrowsable(EditorBrowsableState.Never)]
public bool XmlSomeValueSpecified { get { return SomeValue.HasValue; } }

これにより、妥協することなくユーザーに適切なインターフェイスが提供され、シリアル化時にも適切な処理が行われます。


1
SomeValueはnullの可能性があるため... public double XmlSomeValue {get {return SomeValue.HasValue?SomeValue.Value:0; }セット{SomeValue = value; }}
Doug Domeny 2009年

ヌルXmlSomeValueのみすなわちSomeValue.Value(XmlSomeValueSpecifiedがtrueの場合にのみ触れますのXmlSerializerが使用することになっているではありません。
デビッド・シュミット

@pettys:XMLですが、何を期待していますか?;-)
デビッドシュミット

受け入れられた答えは2008年からです。これは今のはずです。SpecifiedとShouldSerializeに関連する興味深い答え
-daniloquio

間違いなくトップの答えになるはずです。
tyteen4a03 2017

12

2つのプロパティを利用する回避策を見つけました。int?XmlIgnore属性を持つプロパティと、シリアル化されるオブジェクトプロパティ。

    /// <summary>
    /// Score db record
    /// </summary>        
    [System.Xml.Serialization.XmlIgnore()]
    public int? ID 
    { 
        get 
        { 
            return iID_m; 
        } 
        set 
        { 
            iID_m = value; 
        } 
    }

    /// <summary>
    /// Score db record
    /// </summary>        
    [System.Xml.Serialization.XmlElement("ID",IsNullable = false)]
    public object IDValue
    {
        get
        {
            return ID;
        }
        set
        {
            if (value == null)
            {
                ID = null;
            }
            else if (value is int || value is int?)
            {
                ID = (int)value;
            }
            else
            {
                ID = int.Parse(value.ToString());
            }
        }
    }

このソリューションは、int内のNULLを認識しないクライアント、つまりFlexの「プレースホルダー」値としてNULLをエンコードすることもできるため、優れています。
Kuba Wyrostek 2013年

あなたは、コーディング時にそれを見aviodにXMLシリアル化さプロパティに[EditorBrowsable(EditorBrowsableState.Never)]を追加することができます
アントニオ・ロドリゲス

6

この質問/回答が本当に役に立ちました。Stackoverflowを使用しています。

上記でやっていることをもう少し一般的にしました。私たちが本当に求めているのは、シリアル化動作が少し異なるNullableを持つことです。Reflectorを使用して独自のNullableを構築し、XMLシリアル化を希望どおりに機能させるために、いくつかの点をあちこちに追加しました。かなりうまくいくようです:

public class Nullable<T>
{
    public Nullable(T value)
    {
        _value = value;
        _hasValue = true;
    }

    public Nullable()
    {
        _hasValue = false;
    }

    [XmlText]
    public T Value
    {
        get
        {
            if (!HasValue)
                throw new InvalidOperationException();
            return _value;
        }
        set
        {
            _value = value;
            _hasValue = true;
        }
    }

    [XmlIgnore]
    public bool HasValue
        { get { return _hasValue; } }

    public T GetValueOrDefault()
        { return _value; }
    public T GetValueOrDefault(T i_defaultValue)
        { return HasValue ? _value : i_defaultValue; }

    public static explicit operator T(Nullable<T> i_value)
        { return i_value.Value; }
    public static implicit operator Nullable<T>(T i_value)
        { return new Nullable<T>(i_value); }

    public override bool Equals(object i_other)
    {
        if (!HasValue)
            return (i_other == null);
        if (i_other == null)
            return false;
        return _value.Equals(i_other);
    }

    public override int GetHashCode()
    {
        if (!HasValue)
            return 0;
        return _value.GetHashCode();
    }

    public override string ToString()
    {
        if (!HasValue)
            return "";
        return _value.ToString();
    }

    bool _hasValue;
    T    _value;
}

あなたはあなたのメンバーをintとして持つ能力を失いますか?など(代わりにNullable <int>を使用する必要があります)ただし、それ以外はすべての動作は同じです。


1
これは、スローSystem.ExecutionEngineExceptionのをXmlSerializer.Serialize私に。
マーティンブラウン2014年


1

非常に便利な投稿が大きな助けとなりました。

私はスコットのNullable(Of T)データ型のリビジョンを使用することを選択しましたが、投稿されたコードは、 "xs:nil = 'true'"属性なしであるにもかかわらず、Nullの場合でもNullable要素をシリアル化します。

シリアライザーにタグを完全にドロップさせる必要があったので、構造にIXmlSerializableを実装しました(これはVBにありますが、画像が表示されます)。

  '----------------------------------------------------------------------------
  ' GetSchema
  '----------------------------------------------------------------------------
  Public Function GetSchema() As System.Xml.Schema.XmlSchema Implements System.Xml.Serialization.IXmlSerializable.GetSchema
    Return Nothing
  End Function

  '----------------------------------------------------------------------------
  ' ReadXml
  '----------------------------------------------------------------------------
  Public Sub ReadXml(ByVal reader As System.Xml.XmlReader) Implements System.Xml.Serialization.IXmlSerializable.ReadXml
    If (Not reader.IsEmptyElement) Then
      If (reader.Read AndAlso reader.NodeType = System.Xml.XmlNodeType.Text) Then
         Me._value = reader.ReadContentAs(GetType(T), Nothing)
      End If
    End If
  End Sub

  '----------------------------------------------------------------------------
  ' WriteXml
  '----------------------------------------------------------------------------
  Public Sub WriteXml(ByVal writer As System.Xml.XmlWriter) Implements System.Xml.Serialization.IXmlSerializable.WriteXml
    If (_hasValue) Then
      writer.WriteValue(Me.Value)
    End If
  End Sub

このメソッドは、(foo)Specifiedパターンを使用するよりも優先されます。これは、オブジェクトに冗長なプロパティのバケットロードを追加する必要があるためです。一方、新しいNullableタイプを使用すると、プロパティを再入力するだけで済みます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.