Сериализация XML и проблема DefaultValue ("") в c # - PullRequest
10 голосов
/ 04 мая 2011

у моего свойства класса есть значение по умолчанию, которое будет сериализовано.

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 после сериализации, если пользователь ничего не назначает этому свойству.

, пожалуйста, подскажите, что мне нужно изменить в коде, чтобы получить желаемый результат.

Ответы [ 4 ]

17 голосов
/ 04 мая 2011

В примечании в MSDN :

Атрибут DefaultValueAttribute не заставляет элемент автоматически инициализироваться со значением атрибута.Вы должны установить начальное значение в своем коде.

Удивительно, что DefaultValue регулирует только запись объекта, члены, равные их DefaultValue, не будут записываться.

Вы по-прежнему должны инициализировать элементы до или после загрузки себя, например, в конструкторе.

8 голосов
/ 23 мая 2011

Позвольте мне подробно описать, что происходит.

Когда вызывается метод XmlSerializer Deserialize (), он создает новый объект, используя конструктор по умолчанию. Я полагаю, что к этому объекту не применяются атрибуты DefaultValueAttributes, поскольку предполагается, что ctor по умолчанию должен «лучше знать», как инициализировать значения по умолчанию. С этой точки зрения - это логично.

XmlSerializer не сериализует элементы, значения которых совпадают с отмеченными атрибутом DefaultValue. С некоторой точки зрения такое поведение обусловлено и логикой.

Но когда вы не инициализируете членов в ctor и не вызываете метод deserialize, 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 ()" может быть оформлен как Расширение объекта или использоваться как некоторый статический метод вспомогательного класса.

1 голос
/ 04 мая 2011

Как отметил Хенк Холтерман, этот атрибут не устанавливает значение по умолчанию автоматически.Его цель в основном используется визуальными дизайнерами для сброса свойства к его значению по умолчанию.

0 голосов
/ 28 сентября 2016

Как уже упоминалось, атрибут DefaultValue не инициализирует свойство. Вы можете использовать простой цикл для установки всех свойств:

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

Несмотря на то, что ?.Value может возвращать null, он работает с ненулевыми типами, я проверял это.

Если только немногие из ваших свойств имеют значение по умолчанию, возможно, вам следует установить это значение, только если оно там есть.

Если все свойства должны иметь значение по умолчанию, удалите ?, чтобы получить сообщение об ошибке, если вы забыли одно.

Скорее всего, массивы не будут работать, посмотрите решение MajesticRa, как с этим справиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...