Tomer Gabel's annoying spot on the 'net RSS 2.0
# Sunday, January 18, 2009

Update: I was wrong, and private setters do not appear to work (strange, I’m sure I verified this in my test code, but it didn’t work in practice). See below.

It’s been ages since I used XmlSerializer, or even written meaningful amounts of code in C# for that matter, which is why I was utterly stumped by this problem. Try running this code:

[XmlRoot( "test" )]
public class Test
{
    private readonly string _string1;
    private readonly string _string2;

    public Test( string string1, string string2 )
    {
        _string1 = string1;
        _string2 = string2;
    }

    [XmlAttribute( "attr" )]
    public string String1 { get { return _string1; } }

    [XmlElement( "element" )]
    public string String2 { get { return _string2; } }
}
/// ... XmlSerializer xs = new XmlSerializer( typeof( Test ), "" ); XmlSerializerNamespaces xsn = new XmlSerializerNamespaces(); xsn.Add("", ""); // Gets rid of redundant xmlns: attributes StringWriter pw = new StringWriter(); xs.Serialize( pw, new Test( "1", "2" ), xsn ); Console.WriteLine( pw.GetStringBuilder().ToString() );
You’ll get an InvalidOperationException stating that “Test cannot be serialized because it does not have a parameterless constructor.” A quick look at the documentation (or a search which may lead you to this post on StackOverflow) will get you the answer: add a parameterless constructor and mark it private. Run the test code again and this time no exception will be thrown; however, you probably won’t be expecting this result:
<?xml version="1.0" encoding="utf-16"?>
<test />

The solution? Add a setter to each of your serializable properties. Don’t need a setter because the class is immutable? Mark it as private and you’re good to go. Tough – you’re going to need one anyway, private/internal/protected setters don’t appear to work. If you must use XmlSerializer you should throw a NotImplementedException from these setters, but in my opinion the resulting contract clutter implies you should simply avoid XmlSerializer altogether.

Although this behavior makes sense in light of how XmlSerializer can be used for both serialization and de-serialization, what threw me off was that no exception is thrown – the contract doesn’t require a setter property, and the serializer output is corrupt. Beware!

Sunday, January 18, 2009 5:03:06 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [4] -
Development
Sunday, January 18, 2009 7:30:19 PM (Jerusalem Standard Time, UTC+02:00)
Yes, the xml serializer has its gotcha's.

It should be possible to generate the serialization assembly before production/GA in order to improve performance. I once saw a post - not sure where - that explained how one can use compiler flags in order to generate the serializaiton assembly for one source version (e.g. with public accessors) and then compile the app itself without them (or with them being private).

But of course if you don't *have to* work with the xml serializer it is better to avoid it.
Sunday, January 18, 2009 7:50:32 PM (Jerusalem Standard Time, UTC+02:00)
Well, "better to" is a relative concept. I've successfully worked with XmlSerializer before and it usually saves loads of time. If you want to go with purely immutable classes, though, the clutter just isn't worth it.
Wednesday, January 21, 2009 11:30:07 PM (Jerusalem Standard Time, UTC+02:00)
At least circa .NET 2.0, the entire design behind XmlSerializer is shortsighted.
For example, there's the magic SomeProperySpecified member which is undocumented and is the only way to know whether the SomeProperty element actually exists in the deserialized XML file. And it is the only way to force the serializer to not write an element to the file. Woe unto you if you already have a SomePropertySpecified member in your class.
The entire thing simply looks like a hack that somehow got into release, and now MS have no choice but support.

Are you telling me that even now they still didn't make anything better?
Mickey
Sunday, February 15, 2009 11:12:48 PM (Jerusalem Standard Time, UTC+02:00)
Huh, reminds me of the 'bool ShouldSerializeXXX()' magical methods in WinForms, which are arbitrary methods you add to your control. The 'XXX' corresponds to property names. This method allows the designer to determine, in design time, whether aproperty's value is the default one and thus not requiringassigning in the Form.Designer.cs file. Took me some time to believe it after reading it on MSDN. (For properties of primitive types, you have the DefaultValueAttribute.)
Ilya
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Live Comment Preview
Me!
Send mail to the author(s) Be afraid.
Archive
<May 2013>
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
All Content © 2013, Tomer Gabel
Based on the Business theme for dasBlog created by Christoph De Baene (delarou)