【问题标题】:XML serialization and DefaultValue("") related problem in c#c#中的XML序列化和DefaultValue("")相关问题
【发布时间】:2011-08-18 10:30:44
【问题描述】:

我的类属性具有将被序列化的默认值。

public class DeclaredValue
{
    [XmlElement(ElementName = "Amount", DataType = "double", IsNullable = false), DefaultValue(999)]
    public double Amount { get; set; }

    [XmlElement(ElementName = "Reference2", DataType = "string", IsNullable = false), DefaultValue("")]
    public string Reference2 { get; set; }
}

所以我们创建 DeclaredValue 类的实例并为 Reference2 属性提供值,并且不为 Amount 分配任何内容。因此,当我们序列化类 DeclaredValue 时,在我的 xml 中找不到金额的标记。我提到金额“999”的默认值,然后为什么它在序列化中不起作用。我希望如果不为金额分配任何内容,那么我的 xml 中应该有 amoun 标签,并具有默认值。

要做到这一点,如果用户没有为该属性分配任何内容,我需要以什么方式装饰在序列化后它总是在 xml 中带有默认值的数量属性。

请指导我需要更改代码以获得所需的输出。

【问题讨论】:

    标签: c# .net xml-serialization default-value


    【解决方案1】:

    根据note on MSDN

    DefaultValueAttribute 不会导致 自动成为成员 用属性初始化 价值。您必须设置初始值 在你的代码中。

    有点令人惊讶的是,DefaultValue 只规定了对象的写入,与其 DefaultValue 相等的成员不会被写出。

    您仍然必须在加载自己之前或之后初始化成员,例如在构造函数中。

    【讨论】:

    • 如果我明确设置值,那么 DefaultValue 会做什么。你的链接不存在......所以给我一个小代码。
    • 你很可能需要一个构造函数来设置默认值。
    • 在反序列化填充属性之前调用构造函数。
    • 只是为了确认一下,在这种情况下,在构造函数中设置所需的默认值对我有用。
    • @user728750,默认值用于告诉序列化程序在保存 xml 文件时不要将值写回。在序列化它们时,您可以使用它来保持配置清除默认值。使用默认值,如果当前值不是默认值,序列化程序只会写入流。这就是你使用它的原因
    【解决方案2】:

    让我详细描述一下正在发生的事情。

    当调用 XmlSerializer Deserialize() 方法时,它使用默认构造函数创建一个新对象。我相信它不会对这个对象应用任何 DefaultValueAttributes,因为假设默认 ctor 应该“更好地知道”如何在默认情况下初始化值。从这个角度来看 - 这是合乎逻辑的。

    XmlSerializer 不会序列化与 DefaultValue 属性标记的值相同的成员。从某种角度来看,这种行为也是由逻辑驱动的。

    但是当你不初始化 ctor中的成员并调用反序列化方法时,XmlSerializer看不到对应的xml字段,但它看到该字段/属性有DefaultValueAttribute,序列化器只留下这样的值(根据假设默认构造函数更好地知道如何“默认”初始化一个类)。你有你的零。

    解决方案 要通过这些 DefaultValueAttributes 初始化一个类成员(有时将这些初始化值就位很方便),您可以使用这样简单的方法:

        public YourConstructor()
        {
            LoadDefaults();
        }
    
        public void LoadDefaults()
        {
            //Iterate through properties
            foreach (var property in GetType().GetProperties())
            {
                //Iterate through attributes of this property
                foreach (Attribute attr in property.GetCustomAttributes(true))
                {   
                    //does this property have [DefaultValueAttribute]?
                    if (attr is DefaultValueAttribute) 
                    {
                        //So lets try to load default value to the property
                        DefaultValueAttribute dv = (DefaultValueAttribute)attr;
                        try
                        {
                            //Is it an array?
                            if (property.PropertyType.IsArray)
                            {
                                //Use set value for arrays
                                property.SetValue(this, null, (object[])dv.Value); 
                            }
                            else
                            {
                                //Use set value for.. not arrays
                                property.SetValue(this, dv.Value, null);
                            }
                        }
                        catch (Exception ex)
                        {
                            //eat it... Or maybe Debug.Writeline(ex);
                        }
                    }
                }
            }
        }
    

    这个“public void LoadDefaults()”可以被修饰为对象的扩展,或者用作辅助类的一些静态方法。

    【讨论】:

    • 很好的解释。当标有 [DefaultValue(...)] 的属性没有出现在序列化的 xml 中时,我偶然发现了这个问题,这导致了文件兼容性问题。所以我不得不删除 [DefaultValue(...)] 属性...
    【解决方案3】:

    正如 Henk Holterman 提到的,此属性不会自动设置默认值。它的目的主要是供视觉设计者用来将属性重置为其默认值。

    【讨论】:

    • 能否通过示例代码告诉我,因为事情不清楚。
    • 什么不清楚?该属性没有效果。您只需要在构造函数中初始化属性即可。
    【解决方案4】:

    正如其他人提到的,DefaultValue 属性不会初始化属性。您可以使用一个简单的循环来设置所有属性:

    foreach (var property in GetType().GetProperties())
        property.SetValue(this, ((DefaultValueAttribute)Attribute.GetCustomAttribute(
            property, typeof(DefaultValueAttribute)))?.Value, null);
    

    即使?.Value 可以返回null,它也适用于不可为空的类型,我对此进行了测试。

    如果只有少数属性有默认值,那么您应该只设置默认值。

    如果所有属性都应该有一个默认值,请删除?,如果您忘记了会出现错误。

    很可能,数组不起作用,请参阅 MajesticRa 的解决方案如何处理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-26
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      • 2021-03-28
      • 1970-01-01
      相关资源
      最近更新 更多