Синтаксис XML-сериализации для сериализации свойства readonly

В С# у меня есть класс, который имеет производное свойство, которое должно быть сериализовано через XML. Однако сериализация XML (по умолчанию) не сериализует свойства read = only. Я могу обойти это, задав пустой сеттер следующим образом:

public virtual string IdString
{
    get { return Id.ToString("000000"); }
    set { /* required for xml serialization */ }
}

Но есть ли более чистый семантически правильный способ, не говоря о моей собственной реализации ISerializable?

Ответ 1

Честно говоря, это не кажется мне слишком плохим для меня, если оно документировано

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

/// <summary>
/// Blah blah blah.
/// </summary>
/// <exception cref="NotSupportedException">Any use of the setter for this property.</exception>
/// <remarks>
/// This property is read only and should not be set.  
/// The setter is provided for XML serialisation.
/// </remarks>
public virtual string IdString
{
    get
    {
        return Id.ToString("000000");
    }
    set
    {
        throw new NotSupportedException("Setting the IdString property is not supported");
    }
}

Ответ 2

Короче говоря, нет. С помощью XmlSerializer вы можете либо реализовать IXmlSerializable (что нетривиально), либо написать базовый DTO (который полностью читается-записывается), а затем перевести из модели DTO в вашу основную модель.

Обратите внимание, что в некоторых случаях DataContractSerializer является жизнеспособным вариантом, но он не обеспечивает одинаковый контроль над XML. Однако с помощью DCS вы можете:

[DataMember]
public int Id { get; private set; }

Ответ 3

Чтобы принять решение немного дальше, чтобы десериализация также работала...

public class A
{
    private int _id = -1;

    public int Id
    {
        get { return _id; }
        set
        {
            if (_id < 0)
                throw new InvalidOperationException("...");

            if (value < 0)
                throw new ArgumentException("...");

            _id = value;
        }
    }
}

Это позволит Id установить ровно один раз значение, большее или равное 0. Любые попытки установить его после этого приведут к InvalidOperationException. Это означает, что XmlSerializer сможет установить Id во время десериализации, но после этого он никогда не сможет быть изменен. Обратите внимание, что если свойство является ссылочным типом, вы можете просто проверить значение null.

Это может быть не лучшее решение, если у вас есть много свойств для чтения для сериализации/десериализации, поскольку для этого потребуется много кода шаблона. Тем не менее, я нашел, что это приемлемо для классов с 1-2 свойствами только для чтения.

Все еще взломать, но это, по крайней мере, немного более надежное.