[c#] nullable int 직렬화

nullable int가있는 클래스가 있습니까? xml 요소로 직렬화하도록 설정된 데이터 유형. 값이 null 인 경우 xml serializer가 요소를 직렬화하지 않도록 설정하는 방법이 있습니까?

[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을 반환하기 때문입니다.



답변

XmlSerializer는 ShouldSerialize{Foo}()패턴을 지원 하므로 메서드를 추가 할 수 있습니다.

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

{Foo}SpecifiedXmlSerializer가 해당 패턴을 지원하는지 확실하지 않은 패턴 도 있습니다 .


답변

이 마이크로 패턴을 사용하여 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; } }

이는 사용자에게 타협없이 올바른 인터페이스를 제공하며 직렬화 할 때 여전히 올바른 작업을 수행합니다.


답변

두 가지 속성을 활용하는 해결 방법을 찾았습니다. 정수? 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());
            }
        }
    }


답변

이 질문 / 답변이 정말 도움이되었습니다. 나는 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>를 사용해야 함) 그 외에는 모든 동작이 동일하게 유지됩니다.


답변

불행히도 설명하는 동작은 XmlElementAttribute.IsNullable에 대한 문서에 그대로 정확하게 문서화되어 있습니다.


답변

매우 유용한 게시물이 큰 도움이되었습니다.

Nullable (Of T) 데이터 유형에 대한 Scott의 개정판을 사용하기로 선택했지만 게시 된 코드는 “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 유형을 사용하려면 속성을 다시 입력해야합니다.


답변