开发者

XML serialization and DefaultValue("") related problem in c#

my class property has default value which will be serialize.

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

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

so we create instance of DeclaredValue class and provide value for Reference2 property and do not assign anything for Amount. so when we serialize the class DeclaredValue then no tag found for amount in my xml. i mention default value for amount "999" then why it does not work in serialization. i want that if do not assign anything for amount then amoun tag should be there in my xml with default value.

to do this what way i need to decorate the amount property that it always comes with default value in xml after serialization if user do not assign anything to this property.

please guide me what i need to change in the code to get my desired output.


Per the note on MSDN:

A DefaultValueAttribute will not cause a member to be automatically initialized with the attribute's value. You must set the initial value in your code.

Somewhat surprisingly the DefaultValue only regulates the writing of an object, members that are equal to their DefaultValue will not be written out.

You must still initialize members before or after loading yourself, for example in the constructor.


Let me thoroughly describe what is happening.

When XmlSerializer Deserialize() method is called, it creates a new object using a default constructor. It doesn't apply any DefaultValueAttributes to this object, I beleave, because of assumption that default ctor should "know better" how to initialize values by default. From this point of view - it is logical.

XmlSerializer doesn't serialize members which values are the same as marked by DefaultValue attribute. From some point of view such behavior is driven by logic too.

But when you do not initialize members in ctor and call deserialize method, XmlSerializer see no corresponding xml field, but it see that the field/property has DefaultValueAttribute, serializer just leave such value (according to the assumption that the default constructor knows better how to initialize a class "by defaults"). And you've got your zeros.

Solution To initialize a class members by these DefaultValueAttributes (sometimes it is very handy to have this initialization values just in place) you can use such simple method:

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

This "public void LoadDefaults()", can be decorated as an Extension to object or use as some static method of a helper class.


As Henk Holterman mentionned, this attribut doesn't set the default value automatically. Its purpose is mostly to be used by visual designers to reset a property to its default value.


As others mentioned, the DefaultValue attribute doesn't initialize the property. You could use a simple loop to set all properties:

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

Even though ?.Value could return null, it works with non-nullable types, I tested this.

If only few of your properties have a default value, you should maybe only set the value if it is there.

If all properties should have a default value, remove the ? to get an error if you forgot one.

Most likely, arrays won't work, see MajesticRa's solution how to handle that.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜