Serialize một int nullable


92

Tôi có một lớp với int nullable? datatype được đặt để tuần tự hóa dưới dạng phần tử xml. Có cách nào để thiết lập nó để bộ tuần tự xml sẽ không tuần tự hóa phần tử nếu giá trị là null không?

Tôi đã cố gắng thêm thuộc tính [System.Xml.Serialization.XmlElement (IsNullable = false)], nhưng tôi nhận được một ngoại lệ tuần tự hóa thời gian chạy cho biết có lỗi khi phản ánh loại, vì "IsNullable có thể không được đặt thành 'false "cho kiểu Nullable. Hãy xem xét sử dụng kiểu" System.Int32 "hoặc xóa thuộc tính IsNullable khỏi thuộc tính 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; 
        } 
    }
     ...
}

Lớp trên sẽ tuần tự thành:

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

Nhưng đối với các ID là null, tôi không muốn phần tử ID nào cả, chủ yếu vì khi tôi sử dụng OPENXML trong MSSQL, nó sẽ trả về 0 thay vì null cho một phần tử trông giống như

Câu trả lời:


149

XmlSerializer hỗ trợ ShouldSerialize{Foo}()mẫu, vì vậy bạn có thể thêm một phương pháp:

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

Ngoài ra còn có {Foo}Specifiedmẫu - không chắc liệu XmlSerializer có hỗ trợ mẫu đó hay không.


8
XmlSerializer cũng hỗ trợ mẫu Đã chỉ định [Foo}.
David Schmitt


1
Có cách nào để sử dụng ShouldSerialize <prop> với các thuộc tính được tạo tự động không? tức là không có biến cục bộ.
Jay

1
@Jay: Không cần. Bạn có thể chỉ cần gọi HasValuetrên tài sản.
Steven Sudit

1
@ đánh dấu nếu, đối với thành viên (thuộc tính / trường) Foobạn cũng có public bool FooSpecified {get {...} set {...}}, thì dấu getđược sử dụng để xem có Foonên được tuần tự hóa hay không và dấu setđược gọi khi gán giá trị cho Footrong quá trình giải mã hóa.
Marc Gravell

26

Tôi đang sử dụng mẫu vi mô này để triển khai tuần tự hóa 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; } }

Điều này cung cấp giao diện phù hợp cho người dùng mà không bị ảnh hưởng và vẫn hoạt động đúng khi đăng tuần tự.


1
Vì SomeValue có thể là null ... public double XmlSomeValue {get {return SomeValue.HasValue? SomeValue.Value: 0; } đặt {SomeValue = value; }}
Doug Domeny

XmlSomeValue chỉ nghĩa vụ phải được sử dụng bởi các XmlSerializer người sẽ chỉ chạm vào nó khi XmlSomeValueSpecified là đúng (ví dụ SomeValue.Value không phải là null.
David Schmitt

@pettys: Đó là XML, bạn mong đợi điều gì? ;-)
David Schmitt

Câu trả lời được chấp nhận là từ năm 2008. Câu trả lời này nên là câu trả lời ngay bây giờ. Câu trả lời thú vị liên quan đến rõ vs ShouldSerialize
daniloquio

Chắc chắn nên là câu trả lời hàng đầu.
tyteen4a03

12

Tôi đã tìm ra một cách giải quyết bằng cách sử dụng hai thuộc tính. Một int? thuộc tính XmlIgnore và thuộc tính đối tượng được tuần tự hóa.

    /// <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());
            }
        }
    }

Giải pháp này rất tuyệt vì nó cũng cho phép NULL được mã hóa dưới dạng giá trị "trình giữ chỗ" cho máy khách, không nhận dạng NULL trong int, tức là Flex.
Kuba Wyrostek

Bạn có thể thêm [EditorBrowsable (EditorBrowsableState.Never)] vào thuộc tính được tuần tự hóa xml để aviod nhìn thấy nó khi viết mã
Antonio Rodríguez

6

Wow cảm ơn câu hỏi / câu trả lời này thực sự đã giúp tôi ra ngoài. Tôi trái tim Stackoverflow.

Tôi đã làm cho những gì bạn đang làm ở trên chung chung hơn một chút. Tất cả những gì chúng tôi thực sự đang tìm kiếm là có Nullable với hành vi tuần tự hóa hơi khác. Tôi đã sử dụng Reflector để xây dựng Nullable của riêng mình và thêm một số thứ ở đây và ở đó để tuần tự hóa XML hoạt động theo cách chúng tôi muốn. Có vẻ hoạt động khá tốt:

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;
}

Bạn mất khả năng có thành viên của mình là int? và tiếp tục như vậy (phải sử dụng Nullable <int> thay thế) nhưng khác với điều đó là tất cả các hành vi vẫn giữ nguyên.


1
Điều này ném System.ExecutionEngineExceptionvào XmlSerializer.Serializetôi.
Martin Braun

1

Thật không may, các hành vi bạn mô tả được ghi lại chính xác như vậy trong tài liệu cho XmlElementAttribute.IsNullable.


1

Đăng rất hữu ích đã giúp rất nhiều

Tôi đã chọn thực hiện với bản sửa đổi của Scott cho kiểu dữ liệu Nullable (Of T), tuy nhiên mã được đăng vẫn tuần tự hóa phần tử Nullable khi nó là Null - mặc dù không có thuộc tính "xs: nil = 'true'".

Tôi cần buộc bộ tuần tự loại bỏ hoàn toàn thẻ vì vậy tôi chỉ cần triển khai IXmlSerializable trên cấu trúc (đây là trong VB nhưng bạn có được hình ảnh):

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

Tôi thích phương pháp này hơn là sử dụng mẫu được Chỉ định (foo) vì yêu cầu thêm vô số thuộc tính dư thừa vào các đối tượng của tôi, trong khi sử dụng kiểu Nullable mới chỉ yêu cầu nhập lại các thuộc tính.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.