Friday, September 22, 2006

What Is The Best Way To Use Immutable Atomic Value Types With XML Serialization?

Here are two items from Effective C#: 50 Specific Ways to Improve Your C# by Bill Wagner:

Item 7: Prefer Immutable Atomic Value Types

Immutable types are simple: After they are created, they are constant. If you validate the parameters used to construct the object, you know that it is in a valid state from that point forward. You cannot change the object's internal state to make it invalid. You save yourself a lot of otherwise necessary error checking by disallowing any state changes after an object has been constructed. Immutable types are inherently thread safe: Multiple readers can access the same contents. If the internal state cannot change, there is no chance for different threads to see inconsistent views of the data. Immutable types can be exported from your objects safely. The caller cannot modify the internal state of your objects. Immutable types work better in hash-based collections. The value returned by Object.GetHashCode() must be an instance invariant (see Item 10); that's always true for immutable types.

Not every type can be immutable. If it were, you would need to clone objects to modify any program state. That's why this recommendation is for both atomic and immutable value types. Decompose your types to the structures that naturally form a single entity. An Address type does. An address is a single thing, composed of multiple related fields. A change in one field likely means changes to other fields. A customer type is not an atomic type. A customer type will likely contain many pieces of information: an address, a name, and one or more phone numbers. Any of these independent pieces of information might change. A customer might change phone numbers without moving. A customer might move, yet still keep the same phone number. A customer might change his or her name without moving or changing phone numbers. A customer object is not atomic; it is built from many different immutable types using composition: an address, a name, or a collection of phone number/type pairs. Atomic types are single entities: You would naturally replace the entire contents of an atomic type. The exception would be to change one of its component fields.

Item 25: Prefer Serializable Types

Prefer adding serialization to your types when practical. It should be practical for all types that do not represent UI widgets, windows, or forms. The extra perceived work is no excuse. .NET Serialization support is so simple that you don't have any reasonable excuse not to support it. In many cases, adding the Serializable attribute is enough

But, are immutable atomic value types serializable to XML?

Here is the immutable atomic address structure, pretty much taken straight from Wagner's book:

[Serializable]
public struct Address
{
    private readonly string _street;
    private readonly string _city;
    private readonly string _state;
    private readonly string _zip;
 
    public Address (string street, string city, string state, string zip)
    {
        _street = street;
        _city = city;
        _state = state;
        _zip = zip;
    }
 
    public string Street { get { return _street; } }
    public string City { get { return _city; } }
    public string State { get { return _state; } }
    public string Zip { get { return _zip; } }
}
And here is a class that uses it:
[Serializable]
public class Office
{
    private string _name;
    private Address _address;
 
    public Office() { }
 
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
 
    public Address Address
    {
        get { return _address; }
        set { _address = value; }
    }
}
Now, here is some code that creates an Office and serializes it to XML:
Office office = new Office();
office.Name = "Chicago";
office.Address = new Address("1060 W Addison St", "Chicago", "IL", "60613");
 
XmlSerializer s = new XmlSerializer(typeof (Office), new Type[] {typeof (Address)});
s.Serialize(Console.Out, office);

And here's the output:

<Office>
  <Name>Chicago</Name>
  <Address />
</Office>

Where's the address information?

MSDN explains in XML Serialization Considerations:

Only public properties and fields can be serialized. Properties must have public accessors (get and set methods). If you need to serialize non-public data, use the BinaryFormatter class rather than XML serialization.

My Address properties don't have public set methods, and so aren't in the XML.

Now, I like the immutable type idea. It feels good and clean and right to me for things like Address. And Martin Fowler and Eric Evans agree—they both have descriptions of immutable value objects in their books Patterns of Enterprise Application Architecture and Domain-Driven Design, respectively. So, I really want to use the immutable value type idea. However, I'm going to start using these types over a web service. That means I want a good way to serialize them, where "good" is defined by James Shore in Quality With a Name as

A good software design minimizes the time required to create, modify, and maintain the software while achieving acceptable run-time performance.

And so, the question is: What is the best way to use immutable atomic value types with XML serialization?

 

No comments:

Post a Comment