Null yapılabilir bir int diziselleştirme


92

Null yapılabilir int olan bir sınıfım var mı? veri türü bir xml öğesi olarak serileştirilecek şekilde ayarlandı. Değer boş ise xml serileştiricinin öğeyi serileştirmemesi için bunu ayarlamanın bir yolu var mı?

[System.Xml.Serialization.XmlElement (IsNullable = false)] özniteliğini eklemeyi denedim, ancak türü yansıtan bir hata olduğunu söyleyen bir çalışma zamanı serileştirme istisnası alıyorum, çünkü "IsNullable 'false olarak ayarlanamaz 'Null yapılabilir bir tür için.' System.Int32 'türünü kullanmayı veya IsNullable özelliğini XmlElement özniteliğinden kaldırmayı düşünün. "

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

Yukarıdaki sınıf şu şekilde serileştirilecektir:

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

Ancak boş olan kimlikler için Kimlik öğesini hiç istemiyorum, çünkü MSSQL'de OPENXML kullandığımda, şöyle görünen bir öğe için boş yerine 0 döndürüyor

Yanıtlar:


150

XmlSerializer ShouldSerialize{Foo}()kalıbı destekler , böylece bir yöntem ekleyebilirsiniz:

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

Bir de {Foo}Specifieddesen var - XmlSerializer'ın bunu destekleyip desteklemediğinden emin değilim.


8
XmlSerializer ayrıca [Foo} Belirtilen kalıbı destekler.
David Schmitt 04


1
Otomatik oluşturulan özelliklerle ShouldSerialize <prop> kullanmanın herhangi bir yolu var mı? yani yerel değişken yok.
Jay

1
@Jay: Gerek yok. Sadece HasValuemülkü arayabilirsiniz .
Steven Sudit

1
@mark eğer üye (özellik / alan) Fooiçin de bir a sahipseniz public bool FooSpecified {get {...} set {...}}, o zaman serileştirilip gösterilmeyeceğini getgörmek için kullanılır Foove seriyi setkaldırma Foosırasında bir değer atarken çağrılır .
Marc Gravell

26

Nullable serileştirmeyi uygulamak için bu mikro modeli kullanıyorum:

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

Bu, ödün vermeden kullanıcıya doğru arabirimi sağlar ve serileştirirken yine de doğru olanı yapar.


1
SomeValue boş olabileceğinden ... public double XmlSomeValue {get {return SomeValue.HasValue? SomeValue.Value: 0; } set {SomeValue = value; }}
Doug Domeny

XmlSomeValue, yalnızca XmlSomeValueSpecified doğru olduğunda dokunacak olan XmlSerializer tarafından kullanılmalıdır (yani, SomeValue.Value boş değildir.
David Schmitt

@pettys: XML, ne bekliyorsunuz? ;-)
David Schmitt

Kabul edilen cevap 2008'den. Bu, şimdi olmalıdır. Specified vs
ShouldSerialize

Kesinlikle en iyi cevap olmalı.
tyteen4a03

12

İki özelliği kullanan bir geçici çözüm buldum. Bir int? XmlIgnore niteliğine sahip özellik ve serileştirilmiş bir nesne özelliği.

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

Bu çözüm harikadır çünkü NULL’ün, ints’teki NULL’ları, yani Flex’i tanımayan istemciler için "yer tutucu" değeri olarak kodlanmasına izin verir.
Kuba Wyrostek

[EditorBrowsable (EditorBrowsableState.Never)] öğesini kodlama sırasında aviod'un görmesi için xml serileştirilmiş özelliğe ekleyebilirsiniz
Antonio Rodríguez

6

Vay canına, bu soru / cevap bana gerçekten yardımcı oldu. Stackoverflow'u seviyorum.

Yaptığınız şeyi biraz daha genel yaptım. Gerçekten aradığımız tek şey, biraz farklı serileştirme davranışına sahip Nullable'a sahip olmak. Reflector'ı kendi Nullable'ımı oluşturmak için kullandım ve XML serileştirmenin istediğimiz gibi çalışmasını sağlamak için birkaç şey ekledim. Oldukça iyi çalışıyor gibi görünüyor:

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

Üyelerinizi int olarak alma yeteneğinizi mi kaybettiniz? ve benzeri (bunun yerine Nullable <int> kullanmanız gerekir) ancak bunun dışında tüm davranışlar aynı kalır.


1
Bu atar System.ExecutionEngineExceptionAÇIK XmlSerializer.Serializebana.
Martin Braun

1

Ne yazık ki, tanımladığınız davranışlar, XmlElementAttribute.IsNullable belgelerinde olduğu gibi doğru bir şekilde belgelenmiştir.


1

Çok faydalı paylaşımlar çok yardımcı oldu.

Scott'ın Nullable (Of T) veri türündeki revizyonunu seçtim, ancak gönderilen kod, "xs: nil = 'true" özniteliği olmasa da Null olduğunda Nullable öğesini yine de serileştiriyor.

Serileştiriciyi etiketi tamamen bırakması için zorlamam gerekiyordu, bu yüzden yapıya IXmlSerializable'ı uyguladım (bu VB'de ama resmi aldın):

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

Bu yöntemi (foo) Belirtilen kalıbı kullanmayı tercih ederim çünkü bu, nesnelerime yedek özelliklerin kova yüklerini eklemeyi gerektirir, oysa yeni Nullable türü kullanmak yalnızca özelliklerin yeniden yazılmasını gerektirir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.