WCF DataContract сериализация свойств только для чтения?

Всякий раз, когда я использую WCF, я всегда стараюсь создавать неизменяемые классы, которые в конечном итоге проходят через провод (т.е. параметры, установленные в конструкторе, свойства доступны только для чтения). Однако это мешает сериализации WCF, которая требует, чтобы все свойства были Public get/set (что имеет смысл, поскольку оно должно десериализовать их).

Даже в этом связанном сообщении, я вижу, что их решение в конечном итоге делает все Public, что нарушает мое чувство хорошего программирования. Есть ли способ обойти это? Должен ли я просто соглашаться на это решение или что-то вроде неизменяемости печенья и быть счастливым с ним?

Другое, что я пробовал, было что-то вроде этого, где у меня был бы базовый класс для всего и производный класс, который сделал набор бесполезным:

/// <summary>
/// This represents a discovered virtual-machine template that can be
/// instantiated into a RunningVirtualMachine
/// </summary>
[DataContract]
[XmlRoot("VMTemplate")]
public class VirtualMachineTemplateBase
{
    [DataMember]
    public virtual ulong SizeInBytes { get; set; }
}

/// <summary>
/// This class is the real guts of VirtualMachineTemplate that we're hiding
/// from the base class.
/// </summary>
[XmlInclude(typeof(VirtualMachineTemplateBase))]
public class VirtualMachineTemplate : VirtualMachineTemplateBase, IXmlPicklable, IEnableLogger
{
    ulong _SizeInBytes;
    public override ulong SizeInBytes {
        get { return _SizeInBytes; }
        set { }
    }
}

Ответы

Ответ 1

Если вы используете DataContractSerializer (который по умолчанию используется для WCF), вы можете сериализовать anyhting, украшенный атрибутом [DataMember], даже поле только для чтения:

[DataContract]
public class VirtualMachineTemplate : VirtualMachineTemplateBase, IXmlPicklable, IEnableLogger
{
    [DataMember]
    ulong _SizeInBytes;
}

Но вам нужно использовать DataContractSerializer, а не XML-сериализатор. Сериализатор XML может ТОЛЬКО сериализовать общедоступные свойства (и это произойдет, если вы не поместите на них [XmlIgnore]).

Узел DataContractSerializer отличается:

  • ему не нужен конструктор по умолчанию без параметров
  • он будет сериализовать то, что вы явно отмечаете с помощью [DataMember]
  • но это может быть что угодно - поле, свойство и любая видимость (закрытая, защищенная, общедоступная)
  • это немного быстрее, чем XmlSerializer, но вы не получаете большого контроля над формой XML - вы получаете только сообщение о том, что включено

Смотрите это сообщение в блоге и этот сообщение в блоге для нескольких советов и трюков.

Марк

Ответ 2

Для обеспечения как неизменности, так и простой реализации в то же время добавьте частный сеттер для свойства, предназначенного для десериализации. Многое происходит под капотом, но оно работает.