如果它为空或为空,如何从序列化中忽略可为空的属性?

Posted

技术标签:

【中文标题】如果它为空或为空,如何从序列化中忽略可为空的属性?【英文标题】:How to ignore a nullable property from serialization if it is null or empty? 【发布时间】:2013-04-16 20:36:11 【问题描述】:

我有一个用于 Xml 序列化的类。

在其中我有一个可以为空的属性,用 XmlAttribute 装饰:

 [XmlAttribute("lastUpdated")]
 public DateTime? LastUpdated  get; set; 

如果属性为空或为空,如何从序列化中忽略该属性?

我已经尝试了以下方法,但是当有值时它不会序列化(总是忽略):

  [XmlIgnore]
        public DateTime? LastUpdatedValue  get; set; 

        [XmlAttribute("lastUpdated")]
       public DateTime LastUpdated  get; set; 

        public bool ShouldSerializeLastUpdated()
        
            return LastUpdatedValue.HasValue;
        

【问题讨论】:

你看过这个***.com/questions/244953/… 您希望 XML 是什么样子?在这种情况下,如果属性为 null,您将获得 <lastUpdated xsi:nil="true"/>;您可以对 xml 进行后处理(更容易),也可以编写一个 XmlWriter 类(更难,性能更好)。还有其他一些选项既困难又使您的代码膨胀。 不,如果 xmlattribute 为空,我只想忽略它。但是日期时间?不可序列化。怎么换? 【参考方案1】:

XmlSerialization 不直接支持 Nullable。

如果你想使用一个可以为空的属性,你必须使用一个不可为空的属性,并添加一个与属性同名的布尔属性,后缀为“指定”,指定何时该属性必须是可序列化的。

你的例子:

    private DateTime? _lastUpdated;

    [XmlAttribute("lastUpdated")]
    public DateTime LastUpdated 
        get 
            return (DateTime)_lastUpdated;
        
        set
        
            _lastUpdated = value;
        
    

    public bool LastUpdatedSpecified
    
        get
        
            return _lastUpdated.HasValue;
        
    

【讨论】:

谢谢,但问题是我无法再使用 XmlSerializer 对其进行序列化。我收到了这个错误:+ InnerException “有一个错误反映属性'LastUpdated'。” System.Exception System.InvalidOperationException 对不起,我太快了,我更正并编辑了我的代码。你可以试试这个吗? @TheLight 你能接受我的回答,比如最佳回复吗? 如果_lastUpdated 没有值,return (DateTime)_lastUpdated; 将抛出InvalidOperationException LastUpdatedSpecified 用在哪里?【参考方案2】:

我知道这个话题很老了。这是我带来的解决方案。封装类型的类,并隐式转换为类型。序列化时,成员变量可以用IsNullable = false标记,不会出现编译器错误,并且在为null时阻止它被序列化。

public class Optional<T> where T : struct, IComparable

    public Optional(T valueObject)
    
        Value = valueObject;
    

    public Optional()
    
    

    [XmlText]
    public T Value  get; set; 

    public static implicit operator T(Optional<T> objectToCast)
    
        return objectToCast.Value;
    

    public static implicit operator Optional<T>(T objectToCast)
    
        return new Optional<T>(objectToCast);
    

然后在你的课堂上使用它

[Serializable]
[XmlRoot(ElementName = "foo")]
public class foo

   [XmlElement(ElementName = "myInteger", isNullable = false)]
   Optional<int> myInt;

你可以做类似的事情

        myFoo.myInt = 7;
        int j = 8 + myFoo.myInt;

出于所有目的,它是一个 int。出于序列化目的,它可以为 null 并阻止被序列化。

【讨论】:

谢谢,这对我来说很好用!当将它与另一个自定义数据类型一起使用时(我的布尔值需要序列化为 Y/N),我已将 IComparable 更改为 IComparable,我可以在我的 CustomBool 类型中实现 IComparable 这不适用于 [XmlElement(DataType="date")]。 “日期”是 XmlElementAttribute.DataType 属性的无效值。该属性只能为原始类型指定。【参考方案3】:

这对我有用。

    [XmlIgnore]
    public float? Speed  get; set; 

    [XmlAttribute("Speed")]
    public float SpeedSerializable
    
        get
        
            return this.Speed.Value;
        
        set  this.Speed = value; 
    

    public bool ShouldSerializeSpeedSerializable()
    
          return Speed.HasValue;
    

【讨论】:

【参考方案4】:

您可以使用XmlElementAttribute.IsNullable

[Serializable]
public class Result

    [XmlElement(IsNullable = true)]
    public DateTime? LastUpdated   get; set; 

【讨论】:

它不能与属性一起使用。它仅用于元素。【参考方案5】:

注意:这肯定适用于 WCF 中的 SOAP 合同。我没有在其他 Xml 序列化场景中测试过。

当使用[DataContract] 时,您可以使用

[DataMember(EmitDefaultValue = false)]

对于boolean,它只会发出true 的值。 对于nullable boolean,它只会在不是null 时发出。 对于string,它只会在不是null 时发出值。 对于int,它只会在不是0 时发出值。

等等

确保将[DataContract] 放在类本身上,将[DataMember] 放在要序列化的所有成员上,无论您是否指定EmitDefaultValue

不建议将 EmitDefaultValue 属性设置为 false 实践。只有在有特殊需要时才应该这样做 (例如为了互操作性或减少数据大小)。

https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datamemberattribute.emitdefaultvalue(v=vs.110).aspx

【讨论】:

以上是关于如果它为空或为空,如何从序列化中忽略可为空的属性?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查数据读取器是不是为空或为空

检查字符串是不是为空或为空的最简单方法

Oracle/SQL - 在另一个表中查找或为空或可能不存在或为空的记录

XmlSerializer 和可为空的属性

如何在 iOS 中检查 NSArray 是不是为空或为空?

当值为空或为空时如何返回默认值