6

We have an xml document with some user settings. We just added a new setting (which is not found in legacy xml documents) and the XmlSerializer automatically sets it to false. I tried DefaultValueAttribute but it doesn't work. Any idea on how I can get the default value to be true? This is the code:

private bool _property = true;
[DefaultValueAttribute(true)]
public bool Property 
{
    get { return _property; }
    set
    {
        if (_property != value)
        {
            _property = value;
            this.IsModified = true;
        }
    }
}

Thanks!

Carlo
  • 25,602
  • 32
  • 128
  • 176

5 Answers5

11

DefaultValue affects the serialization insofar as if at runtime the property has a value that matches what the DefaultValue says, then the XmlSerializer won't actually write that element out (since it's the default).

I wasn't sure whether it would then affect the default value on read, but it doesn't appear to do so in a quick test. In your scenario, I'd likely just make it a property with a backing field with a field initializer that makes it 'true'. IMHO I like that better than ctor approach since it decouples it from the ctors you do or don't have defined for the class, but it's the same goal.

using System;
using System.ComponentModel;
using System.Xml.Serialization;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        var serializer = new XmlSerializer(typeof(Testing));

        string serializedString;
        Testing instance = new Testing();
        using (StringWriter writer = new StringWriter())
        {
            instance.SomeProperty = true;
            serializer.Serialize(writer, instance);
            serializedString = writer.ToString();
        }
        Console.WriteLine("Serialized instance with SomeProperty={0} out as {1}", instance.SomeProperty, serializedString);
        using (StringReader reader = new StringReader(serializedString))
        {
            instance = (Testing)serializer.Deserialize(reader);
            Console.WriteLine("Deserialized string {0} into instance with SomeProperty={1}", serializedString, instance.SomeProperty);
        }
        Console.ReadLine();
    }
}

public class Testing
{
    [DefaultValue(true)]
    public bool SomeProperty { get; set; }
}

As I mentioned in a comment, the page on the xml serialization attributes (http://msdn.microsoft.com/en-us/library/83y7df3e.aspx) claims that the DefaultValue will indeed make the serializer set the value when it's missing, but it doesn't do so in this test code (similar to above, but just deserializes 3 inputs).

using System;
using System.ComponentModel;
using System.Xml.Serialization;
using System.IO;

class Program
{
    private static string[] s_inputs = new[]
    {
        @"<?xml version=""1.0"" encoding=""utf-16""?>
          <Testing xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" />",

        @"<?xml version=""1.0"" encoding=""utf-16""?>
          <Testing xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
              <SomeProperty />
          </Testing>",

        @"<?xml version=""1.0"" encoding=""utf-16""?>
          <Testing xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
              <SomeProperty>true</SomeProperty>
          </Testing>",
    };

    static void Main(string[] args)
    {
        var serializer = new XmlSerializer(typeof(Testing));

        foreach (var input in s_inputs)
        {
            using (StringReader reader = new StringReader(input))
            {
                Testing instance = (Testing)serializer.Deserialize(reader);
                Console.WriteLine("Deserialized string \n{0}\n into instance with SomeProperty={1}", input, instance.SomeProperty);
            }
        }
        Console.ReadLine();
    }
}

public class Testing
{
    [DefaultValue(true)]
    public bool SomeProperty { get; set; }
}
James Manning
  • 13,429
  • 2
  • 40
  • 64
  • You're right, this doesn't work. What did work though was to just set the default value in the class constructor as suggested in the other posts below. – Miguel Sevilla Jan 04 '14 at 01:28
4

Regardless of how it is documented to work, I also do not see DefaultValue being assigned when deserializing. The solution for me was simply set the default value within the class constructor and give up on DefaultValueAttribute.

James
  • 1,973
  • 1
  • 18
  • 32
  • This is a good solution to the DefaultValueAttribute not working. – Miguel Sevilla Jan 04 '14 at 01:29
  • If you set a default value on an attribute and the attribute is missing, it works as expected. If you set a default value on an element and the element _content_ is empty, it works as expected; however, if the element is _missing_, an empty value is assigned on deserialization. This is standard XML behavior, which is pretty useless. Setting a default value in the constructor is more sensible. – Suncat2000 Mar 05 '20 at 17:46
1

About Scott's last reply.

The default constructor sets any array property to "null" when no elements are found. I've set the property to a new empty array (so an instance of an empty array), but the XmlSerializer bypasses this when doing its deserialization and sets it to "null".

Example of the class:

[XmlElement("Dtc")]
public DtcMarketMapping[] DtcMarketMappingInstances
{
    get { return dtcMarketMappingInstances; }
    set { dtcMarketMappingInstances = value; }
}

It might however be something specific to arrays and your answer is still valid about setting default values to simple properties in the class' constructor.

Anyways, thanks for the answers everyone.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Adeynack
  • 1,200
  • 11
  • 18
  • Arrays are really awkward to read/write with xml. Maybe if it is a fixed size array which is allocated in the constructor, but I have thus far ended up using lists rather than arrays for any field that is an XmlElement because they just-work. – James Jul 31 '14 at 22:49
0

Set the default value in the constructor. The value will only be changed during deserialize if it exists in the file.

public class MySettingsClass
{
    public MySettingsClass()
    {
        _property = true;
    }

    private bool _property = true;
    public bool Property 
    {
        get { return _property; }
        set
        {
            if (_property != value)
            {
                _property = value;
                this.IsModified = true;
            }
        }
    }
}
Daniel
  • 1,044
  • 11
  • 10
-1

The DefaultValueAttribute doesn't actually do anything to your running code. It is (mostly) used by property browsers (such as when you bind your object to a PropertyGrid) to know what the default value should be so they can do something "special" when the value is different than the default. That's how the property grid in Visual Studio knows when to make a value bold (showing that it's different than the default value.

The XmlSerializer is setting it your _property field to false because that is the .NET Framework default value for a bool.

The simplest way to accomplish this would probably be to use a default class constructor and set the value there.

Scott Dorman
  • 42,236
  • 12
  • 79
  • 110
  • 2
    It's not true that it does nothing to the running code. Without the default value, you can not even deserialize in some cases. If you look at the [generated code](http://msdn.microsoft.com/en-us/library/aa302290.aspx). The DefaultValue doesn't set a default value when deserializing, which is pretty unintuitive. However, it does cause the generated code to skip empty elements. – Matthew Flaschen Jul 07 '12 at 02:08
  • I voted up because you bring a good point about the PropertyGrid. But THe XmlSerializer seams to use the DefaultValueAttribute also which could give headache. Sometimes I want a DefaultValue for my propertyGrid but still want to serialize my value (in any case) to ensure that any changes to my DefaultValue (in the future) would let the code run as previously. – Eric Ouellet Jul 28 '15 at 18:03
  • When serializing, if the value matches the `DefaultValueAttribute`, the attribute or element will not be serialized. If it's an element, this is actually a bug in `XmlSerializer`, because an element may have empty _content_, but must not be _omitted_; it is only not a bug when omitted if `minOccurs=0` in the XML schema. – Suncat2000 Mar 05 '20 at 18:08