Saturday, June 26, 2010

Serialization should eat its own dog food

@YaronNaveh

An enum in c# can be used as a bit field by adding the Flags attribute:


[Flags]
public enum Groups
{
   Admins = 1,
   Users = 2,
   Guests = 4,
   RemoteUsers = 8
}


We can then define a class that uses it:


[DataContract]
public class User
{
   [DataMember]
   public Groups Groups {get; set;}
}


When we serialize an instance of the class, with either .Net 2.0 serialization or data contract serialization, we get something like this:


...
<Groups>Admins RemoteUsers</Groups>
...


assuming the active flags are Admins and RemoteUsers.

If we deserialize this back to the class everything works fine. But what if the xml needs to be manually parsed for some reason and we need to do something like this:


Enum.Parse(typeof(Groups), "Admins RemoteUsers");


We would get this exception:


Requested value 'Admins RemoteUsers' was not found.


The reason is that Enum.Parse expects a comma between the values and not a space. So this fails:


Enum.Parse(typeof(Groups), "Admins RemoteUsers");


while this work:


Enum.Parse(typeof(Groups), "Admins,RemoteUsers");


Since a space is not valid inside an enum member we can safely do this when reading from the xml:


Enum.Parse(typeof(Groups), value.Replace(" ", ","));


Which will work.

However in the general case manually deserializing a value is dangerous. For example the enum may contain serialization flags:


[Flags]
public enum Groups
{
   [XmlEnum(Name="administrators")]
   Admins = 1,
...
}


This will affect the resulting xml:


...
<Groups>administrators RemoteUsers</Groups>
...


and Enum.Parse will fail. So it is always better to let whoever generated the xml from the first place to eat its own dog food and deserialize it back.

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

0 comments: