Mam klasę z wartością nullable int? typ danych ustawiony na serializację jako element xml. Czy istnieje sposób, aby skonfigurować to tak, aby serializator xml nie serializował elementu, jeśli wartość jest równa null?
Próbowałem dodać atrybut [System.Xml.Serialization.XmlElement (IsNullable = false)], ale pojawia się wyjątek serializacji środowiska wykonawczego z informacją, że wystąpił błąd odzwierciedlający typ, ponieważ „IsNullable może nie być ustawiona na„ false ” 'dla typu dopuszczającego wartość null. Rozważ użycie typu „System.Int32” lub usunięcie właściwości IsNullable z atrybutu 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;
}
}
...
}
Powyższa klasa będzie serializowana do:
<Score xmlns="http://mycomp.com/test/score/v1">
<ID xsi:nil="true" />
</Score>
Ale w przypadku identyfikatorów, które są zerowe, w ogóle nie chcę elementu ID, głównie dlatego, że kiedy używam OPENXML w MSSQL, zwraca 0 zamiast null dla elementu, który wygląda jak
źródło
HasValue
do nieruchomości.Foo
masz również elementpublic bool FooSpecified {get {...} set {...}}
,get
służy do sprawdzenia, czyFoo
powinien być serializowany, aset
jest wywoływany podczas przypisywania wartości doFoo
podczas deserializacji.Używam tego mikro-wzorca do implementacji serializacji 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; } }
Zapewnia to użytkownikowi właściwy interfejs bez kompromisów i nadal działa właściwie podczas serializacji.
źródło
Znalazłem obejście z wykorzystaniem dwóch właściwości. Int? właściwość z atrybutem XmlIgnore i właściwością obiektu, która jest serializowana.
/// <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()); } } }
źródło
Wow, dzięki, to pytanie / odpowiedź naprawdę mi pomogło. Serce Stackoverflow.
Sprawiłem, że to, co robisz, było trochę bardziej ogólne. Wszystko, czego naprawdę szukamy, to mieć wartość Nullable z nieco innym zachowaniem serializacji. Użyłem Reflectora do zbudowania własnej wartości Nullable i dodałem kilka rzeczy tu i tam, aby serializacja XML działała tak, jak chcemy. Wydaje się, że działa całkiem nieźle:
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; }
Tracisz możliwość posiadania członków jako int? i tak dalej (zamiast tego należy użyć Nullable <int>), ale poza tym wszystkie zachowania pozostają takie same.
źródło
System.ExecutionEngineException
ONXmlSerializer.Serialize
na mnie.Niestety opisane zachowania są dokładnie udokumentowane jako takie w dokumentacji XmlElementAttribute.IsNullable.
źródło
Bardzo przydatne posty bardzo pomogły.
Zdecydowałem się przejść z wersją Scotta do typu danych Nullable (Of T), jednak wysłany kod nadal serializuje element Nullable, gdy ma wartość Null - aczkolwiek bez atrybutu „xs: nil = 'true'”.
Musiałem wymusić na serializatorze całkowite usunięcie tagu, więc po prostu zaimplementowałem IXmlSerializable na strukturze (to jest w VB, ale masz zdjęcie):
'---------------------------------------------------------------------------- ' 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
Wolę tę metodę niż użycie wzorca (foo) Specified, ponieważ wymaga to dodania ładunków zasobnika nadmiarowych właściwości do moich obiektów, podczas gdy użycie nowego typu Nullable wymaga tylko ponownego wpisania właściwości.
źródło