Принудительная сериализация XML для сериализации свойства только для чтения - PullRequest
33 голосов
/ 07 апреля 2011

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

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

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

Ответы [ 3 ]

19 голосов
/ 08 апреля 2011

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

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

/// <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");
    }
}
14 голосов
/ 07 апреля 2011

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

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

[DataMember]
public int Id { get; private set; }
1 голос
/ 15 января 2016

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

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 во время десериализации, но его никогда не удастся изменить после. Обратите внимание, что если свойство является ссылочным типом, вы можете просто проверить его на нулевое значение.

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

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

...