1

I'm using XML serialization to produce a file in a format specific to another application. One of the requirements is that all booleans be represented as 1 or 0. I've looked at some possibilities, including a struct to handle this easily and seamlessly. Currently I'm looking into another venue, which is to use an enum.

public enum BoolEnum
{
    [XmlEnum("0")]
    False = 0,
    [XmlEnum("1")]
    True = 1
}

So far, it works wonderfully, and it's much cleaner. BUT (!) I'm also trying to make the deserialization easy, and I'd just like to be able to handle errors. If I produce an invalid tag:

<invalid>2</invalid>

to be deserialized as BoolEnum, I get an InvalidOperationException inside another InvalidOperationException. How can I catch that exception in an enum?


Addendum:

Deserialization function:

static void Deserialize<T>(out T result, string sourcePath) where T : class
{
    FileStream fileStream = null;

    try
    {
        fileStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read);
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        result = xmlSerializer.Deserialize(fileStream) as T;
    }
    finally
    {
        if (fileStream != null)
            fileStream.Close();
    }
}

Deserialized object:

public class Test
{
    [XmlElement("someboolvalue")
    public BoolEnum SomeBoolValue { get; set; }
}
Community
  • 1
  • 1
MPelletier
  • 16,256
  • 15
  • 86
  • 137
  • what is the outer exception which contain InvalidOperationException ? can you show how you deserialize and what throws? – Davide Piras Sep 17 '11 at 14:36
  • @Davide the InvalidOperationException is in another InvalidOperationException. I also added more code. xmlSerializer.Deserialize is the function that throws. – MPelletier Sep 17 '11 at 14:48
  • Wrap your fileStream with a using block and put a catch anyway so to log exceptions while Deserializing. – Davide Piras Sep 17 '11 at 14:55
  • @Davide: But that would basically trigger on any deserializer issue. I'd just like to handle this specific case at a more localized level. – MPelletier Sep 17 '11 at 15:11

2 Answers2

3

I'd just like to be able to handle errors

You can use attributes to expose certain properties to Xml serialization, and hide other properties from it. Likewise you can expose certain properties to be visible via Intellisense, and hide others.

You can take advantage of this fact to use a different code-visible property type from the underlying serialization. This will allow you to use a bool in code, and an int in serialization.

If you choose this route, you can add custom serialization code to handle this case in the int property's getter/setter methods. E.g.

[XmlIgnore]
public bool SomeValue { get; set; }

[EditorBrowsable(EditorBrowsableState.Never)]
[XmlElement("SomeValue")]
public int SomeValueForSerialization
{
    get
    {
        return SomeValue ? 1 : 0;
    }
    set
    {
        SomeValue = value != 0;
        // Or do strict validation, and throw whatever exception you'd like.
        // Preferably one the serializer will already throw, tho :)
    }
}
Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183
  • Note that with your edits, I'd still prefer this method to replacing a generic boolean with an enum (although replacing a domain-specific boolean with an enum sometimes makes sense - e.g. read-only vs read-write if those are your only two states, and would otherwise be a `bool`). – Merlyn Morgan-Graham Sep 17 '11 at 14:49
  • If you want, you can take a look at [my question on CodeReview](http://codereview.stackexchange.com/questions/4829/presenting-a-boolean-as-an-int-for-xmlserialization-in-c). What you wrote is essentially my first design (minus my clutter). – MPelletier Sep 17 '11 at 14:58
  • @MPelletier: If this type is in a separate assembly, it hides the serialization clutter due to the `EditorBrowsable`. You can also use an Xml schema to do in-line validation, rather than having to write the validation/exception throwing code yourself: http://stackoverflow.com/questions/1705430/xmlserializer-validation – Merlyn Morgan-Graham Sep 17 '11 at 15:09
  • I like your solution, but I have to find a way to make it reusable for the various bools. I'll play around with it. – MPelletier Sep 17 '11 at 15:09
  • @MPelletier: You could look into using some sort of code generation to solve the reusability aspect, e.g. [PostSharp](http://www.sharpcrafters.com/). – Merlyn Morgan-Graham Sep 17 '11 at 15:11
0

I generally prefer to keep complex persistence as a separate feature of a class.

I use a combination of XElement and extension methods to make persistence clear and concise, for example:

public static int AsZeroOrOneElelementNamed(this bool theBool, string name)
{
    return new XElement( name, theBool ? 1 : 0 ) ;
}

then, in your type:

public XElement AsXml( )
{
    return new XElement(@"ThisThing",
        _myBoolean.AsZeroOrElementNamed(@"MyBoolean"),
        _myString.AsElementNamed(@"MyString"));
}

This gets rid of the clutter of XML attributes which makes the clearer and cleaner and leaves the persistence aspect to a method who's only responsibility is serialisation.

But for very simple persistence, e.g. where I don't to clutter my types with any attributes, then I use the built in persistence.

MPelletier
  • 16,256
  • 15
  • 86
  • 137
Steve Dunn
  • 21,044
  • 11
  • 62
  • 87
  • The problem with this approach is that it doesn't use the built-in XML serialization, so it won't be as compatible with existing code. You'd have to build such code into every class you want to nest in an object tree. – Merlyn Morgan-Graham Sep 17 '11 at 15:28
  • @Merlyn, when you say "the problem with this approach is that it doesn't use the built-in XML serialization": for complex scenarios, the problem IS the built in XML serialization! For general purpose stuff, I do prefer the in-built stuff, but, and I don't know if it's just me, when I need to pollute my code with attributes, I feel like I'm mixing concerns and responsibilities. For MPelletier's case, serialization is a special enough concern to warrant something other than the in-built stuff. I would maybe even have a separate type that reflects over the DTOs to produce this bespoke XML. – Steve Dunn Sep 17 '11 at 16:02
  • Yep, it's not just you. Check out a related topic - [Data Contract Surrogates](http://msdn.microsoft.com/en-us/library/ms733064.aspx). This shows that even the framework designers consider serialization a necessarily separate concern from the object itself. If you're not using the data contract serializer it is perfectly fine to implement your messy serialization behavior in a persistence layer ([DAL](http://en.wikipedia.org/wiki/Data_access_layer)), complete with its own object hierarchy for your data model. I'd still try at first to use the `XmlSerializer` there. – Merlyn Morgan-Graham Sep 17 '11 at 21:11