Как безопасно проверить неинициализированное значение при десериализации

#c# #serialization

#c# #сериализация

Вопрос:

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

Это работает нормально, если какой-либо элемент ОТСУТСТВУЕТ в потоке. Как бы то ни было, мой вопрос в том, что в случае, если элемент ОТСУТСТВУЕТ в потоке, кто может гарантировать, что эти неинициализированные значения равны 0, DateTime.MinValue и null соответственно?

Кроме того, если член int имеет значение 0, как я узнаю, что он из потока или не инициализирован?

 [DataContract]
public class MyData
{
    [DataMember]
    public int MemberA { get; set; }

    [DataMember]
    public DateTime MemberB { get; set; }

    [DataMember]
    public string MemberC { get; set; }

    [OnDeserialized]
    void OnDeserialized(StreamingContext c)
    {
        if (MemberA == 0)
            MemberA = 100;
        if (MemberB == DateTime.MinValue)
            MemberB = DateTime.Now;
        if (MemberC == null)
            MemberC = "MemberC";
    }
}
 

Я ищу лучший подход, что-то вроде

 if (NotInitialized(MemberA))
    MemberA = xxx;
 

Ответ №1:

Вы могли бы рассмотреть возможность использования нулевого типа, который будет автоматически установлен null , если данные отсутствуют во время десериализации:

 [DataMember]
public int? MemberA { get; set; }

[DataMember]
public DateTime? MemberB { get; set; }

[DataMember]
public string? MemberC { get; set; }
 

Обратите внимание на добавление ? к каждому типу значения, которое указывает, что оно также может быть null .

Легко определить, имеют ли они значения:

 if (MemberA.HasValue)
{
    // Value = MemberA.Value;
    ... do something
}
 

Вы также можете убедиться, что элемент не выводится, если вы снова сериализуете класс, используя атрибуты на DataMember :

 [DataMember(IsRequired = false, EmitDefaultValue = false)]
public int? MemberA { get; set; }
 

Это означает, что MemberA оно будет полностью исключено из ваших сериализованных результатов, если оно имеет null значение.

Комментарии:

1. Итак, в случае отсутствия значения из потока, этот тип с нулевым значением будет гарантированно равен null? Можете ли вы показать мне ссылку?

2. Итак, если MemberA.HasValue значение равно false, то значение равно null . Это работает и для int s, поэтому его не будет 0 в случае отсутствия в вашем потоке данных.

3. IsRequired = false означает, что если это значение равно нулю, то не сериализуйте? если EmitDefaultValue = true, как установить значение по умолчанию?

4. Итак, если EmitDefaultValue = true тогда [значение] по умолчанию для элемента должно быть сгенерировано в потоке сериализации . Так что для int этого будет 0 , и так далее. Значение равно значению по умолчанию для этого типа значения.