ทำให้อนุกรมของ int ว่างเปล่า


92

ฉันมีคลาสที่มี int ว่างเปล่า? ประเภทข้อมูลตั้งค่าให้เป็นอนุกรมเป็นองค์ประกอบ xml มีวิธีใดบ้างในการตั้งค่าเพื่อให้ xml serializer จะไม่ทำให้อนุกรมขององค์ประกอบถ้าค่าเป็นโมฆะ

ฉันพยายามเพิ่มแอตทริบิวต์ [System.Xml.Serialization.XmlElement (IsNullable = false)] แต่ฉันได้รับข้อยกเว้นการทำให้เป็นอนุกรมรันไทม์แจ้งว่ามีข้อผิดพลาดที่แสดงถึงประเภทเนื่องจาก "IsNullable อาจไม่ถูกตั้งค่าเป็น 'false "สำหรับประเภท Nullable ให้พิจารณาใช้ประเภท" System.Int32 "หรือลบคุณสมบัติ IsNullable ออกจากแอตทริบิวต์ XmlElement"

[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>

แต่สำหรับ ID ที่เป็นโมฆะฉันไม่ต้องการองค์ประกอบ ID เลยโดยหลักแล้วเพราะเมื่อฉันใช้ OPENXML ใน MSSQL จะส่งคืน 0 แทนค่าว่างสำหรับองค์ประกอบที่ดูเหมือน

คำตอบ:


149

XmlSerializer รองรับShouldSerialize{Foo}()รูปแบบดังนั้นคุณสามารถเพิ่มวิธีการ:

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

นอกจากนี้ยังมี{Foo}Specifiedรูปแบบ - ไม่แน่ใจว่า XmlSerializer รองรับรูปแบบนั้นหรือไม่


8
XmlSerializer ยังรองรับรูปแบบที่ระบุ [Foo}
David Schmitt

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 อาจเป็นโมฆะ ... XmlSomeValue คู่สาธารณะ {รับ {return SomeValue.HasValue? SomeValue.Value: 0; } ตั้งค่า {SomeValue = value; }}
Doug Domeny

XmlSomeValue ควรจะใช้โดย XmlSerializer เท่านั้นที่จะสัมผัสมันก็ต่อเมื่อ XmlSomeValueSpecified เป็นจริง (เช่น SomeValue.Value ไม่เป็นโมฆะ
David Schmitt

@pettys: เป็น XML คุณคาดหวังอะไร ;-)
David Schmitt

คำตอบที่ยอมรับคือตั้งแต่ปี 2008 อันนี้น่าจะเป็นคำตอบในตอนนี้ คำตอบที่น่าสนใจเกี่ยวกับSpecified vs ShouldSerialize
daniloquio

น่าจะเป็นคำตอบอันดับต้น ๆ อย่างแน่นอน
tyteen4a03

12

ฉันพบวิธีแก้ปัญหาโดยใช้คุณสมบัติสองอย่าง 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());
            }
        }
    }

โซลูชันนี้ยอดเยี่ยมเนื่องจากยังช่วยให้ NULL สามารถเข้ารหัสเป็นค่า "ตัวยึดตำแหน่ง" สำหรับไคลเอนต์ที่ไม่รู้จัก NULL ใน ints เช่น Flex
Kuba Wyrostek

คุณสามารถเพิ่ม [EditorBrowsable (EditorBrowsableState.Never)] ลงในคุณสมบัติอนุกรม xml เพื่อให้ aviod เห็นเมื่อเขียนโค้ด
Antonio Rodríguez

6

ว้าวขอบคุณคำถาม / คำตอบนี้ช่วยฉันได้จริงๆ ฉันเป็นหัวใจของ Stackoverflow

ฉันทำให้สิ่งที่คุณกำลังทำอยู่เหนือกว่าทั่วไปเล็กน้อย สิ่งที่เราต้องการจริงๆคือการมี Nullable ที่มีพฤติกรรมการทำให้เป็นอนุกรมที่แตกต่างกันเล็กน้อย ฉันใช้ตัวสะท้อนแสงเพื่อสร้าง 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

1

น่าเสียดายที่พฤติกรรมที่คุณอธิบายนั้นได้รับการบันทึกไว้อย่างถูกต้องในเอกสารสำหรับ XmlElementAttribute.IsNullable


1

การโพสต์ที่มีประโยชน์มากช่วยได้มาก

ฉันเลือกที่จะใช้การแก้ไขของ Scott เป็นประเภทข้อมูล Nullable (Of T) อย่างไรก็ตามรหัสที่โพสต์ยังคงทำให้องค์ประกอบ Nullable เป็นอนุกรมเมื่อเป็น Null - แม้ว่าจะไม่มีแอตทริบิวต์ "xs: nil = 'true'" ก็ตาม

ฉันต้องการบังคับให้ serializer วางแท็กอย่างสมบูรณ์ดังนั้นฉันจึงใช้ 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) เนื่องจากต้องการการเพิ่มคุณสมบัติที่ซ้ำซ้อนลงในออบเจ็กต์ของฉันในขณะที่การใช้ประเภท Nullable ใหม่เพียงแค่ต้องพิมพ์คุณสมบัติใหม่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.