views:

1606

answers:

1

Whenever I use WCF, I always try to make immutable classes that end up going over the wire (i.e. parameters set in constructor, properties are read-only). However, this gets in the way of WCF serialization, which demands that all properties be Public get/set (which makes sense, because it has to deserialize them)

Even in this related post, I see that their solution ended up making everything Public, which violates my sense of good programming. Is there any way around this? Do I have to just settle for this solution or something like popsicle immutability and be happy with it?

The other thing I tried was something like this, where I'd have a base class for everything and a derived class that made the set useless:

/// <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 { }
    }
}
+4  A: 

If you use the DataContractSerializer (which is the default for WCF), you can serialize anyhting that's decorated with the [DataMember] attribute - even a read-only field:

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

But you need to use the DataContractSerializer - not the XML serializer. The XML serializer can ONLY serialize public properties (and it will, unless you put a [XmlIgnore] on them).

The DataContractSerializer is different:

  • it doesn't need a parameter-less default constructor
  • it will only serialize what you explicitly mark with [DataMember]
  • but that can be anything - a field, a property, and of any visibility (private, protected, public)
  • it's a bit faster than XmlSerializer, but you don't get a lot of control over the shape of the XML - you only get a say in what's included

See this blog post and this blog post for a few more tips and tricks.

Marc

marc_s
No, you still need to include the set or it fails.
Craig