nullable int 직렬화


92

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

답변:


149

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

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

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


8
XmlSerializer는 [Foo} 지정 패턴도 지원합니다.
David Schmitt


1
자동 생성 속성과 함께 ShouldSerialize <prop>를 사용하는 방법은 무엇입니까? 즉, 지역 변수가 없습니다.
Jay

1
@Jay : 하나는 필요 없습니다. HasValue숙소로 전화하시면 됩니다.
Steven Sudit 2010 년

1
@mark if, for member (property / field) Fooyou also have a public bool FooSpecified {get {...} set {...}}, then getis used to see if it is Fooserialized, and the setis called when assign a value to Foodeserialization.
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; } set {SomeValue = 값; }}
Doug Domeny 2009-06-05

. XmlSomeValue은 XmlSomeValueSpecified에 해당하는 경우에만, 즉 SomeValue.Value가 null가 아닌 (만지지 것입니다 XmlSerializer를 사용할 수 있도록되어있다
데이비드 슈미트

@pettys : XML입니다. 무엇을 기대하십니까? ;-)
데이비드 슈미트

받아 들여진 대답은 2008 년의 대답입니다.이 대답은 지금이어야합니다. 재미있는 대답 관련 ShouldSerialize 대 지정
daniloquio

확실히 최고의 답변이어야합니다.
tyteen4a03

12

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

이 솔루션은 또한 클라이언트에 대해 NULL을 "자리 표시 자"값으로 인코딩 할 수 있기 때문에 유용합니다.이 값은 int, 즉 Flex에서 NULL을 인식하지 않습니다.
쿠바 Wyrostek

[EditorBrowsable (EditorBrowsableState.Never)]를 xml 직렬화 속성에 추가하여 코딩 할 때 본 aviod
Antonio Rodríguez

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날.
Martin Braun 2014 년

1

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


1

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

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 유형을 사용하려면 속성을 다시 입력해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.