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