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; }
}
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.
- XmlIgnoreAttribute
- EditorBrowsableAttribute
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 :)
}
}
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.
精彩评论