Subscribe:
|
Categories:
ASP.NET
ast_mono
Asterisk
Code
FreeSWITCH
FSharp
Guatemala
Humour
IL
Korean
Mei
Misc
Misc. Technology
Personal
Photography
Security
Spammers
VoIP
Sign In
[Giagnocavo]Michael::Write()
Tuesday, November 25, 2008
XmlSerialization for F# Types
On a current project, I'm using F# with ASMX Web Services (Mono, so no WCF). I started off declaring some types like this:
type Account() =
[<DefaultValue>]
val mutable Name : string
[<DefaultValue>]
val mutable Data : byte array
We have to tag "default value" to tell F# it should go generate the default (Unchecked.defaultof<'a>) -- in this case, null.
Unfortunately, the serialized XML is not what we want. Currently F# generates both a public field ("_Name") and a get/set property ("Name") to access it. I'm not sure why this is, but there's probably some interesting reason (the part of the spec is 10.2.7 Explicit Fields, but it doesn't mention the implementation). The workaround is simple: tag the field with "XmlIgnore".
As of F# 1.9.3.7, you can choose to target an attribute at the property or the field for a val in a class type. See:
http://blogs.msdn.com/dsyme/archive/2007/11/30/full-release-notes-for-f-1-9-3-7.aspx
(I didn't find this part in the spec.)
So, the revised declaration for the XmlSerialization-friendly type is:
type Account() =
[<DefaultValue; field: XmlIgnore>]
val mutable Name : string
[<DefaultValue; field: XmlIgnore>]
val mutable Data : byte array
I found that to add a lot of noise, so I aliased them:
type DV = DefaultValueAttribute
type XI = XmlIgnoreAttribute
type Account() =
[<DV; field: XI>] val mutable Name : string
[<DV; field: XI>] val mutable Data : byte array
Now it works just fine and creates the XML we'd expect.
One other thing might bite you: null. F# rightfully eschews null. If you have a function that returns one of these types, you'll find it won't let you return null:
> let test() : Account = null;;
let test() : Account = null;;
-----------------------^^^^^
stdin(6,24): error FS0043: The type 'Account' does not have 'null' as a proper value.
This is generally good, but unfortunately, interop with the unenlightened world is sometimes necessary. The right way to do this is:
let test() : Account = Unchecked.defaultof<Account>;;
That's a bit too verbose for my liking, since I have to go annotate the type. A simple function will get around that:
> let inline getnull() = Unchecked.defaultof<_>;;
val inline getnull : unit -> 'a
> let test() : Account = getnull();;
val test : unit -> Account
Yes, I know it's not null, but default, but I think the purpose is clear enough.
FSharp
Tuesday, November 25, 2008 2:16:33 AM UTC
Comments [0]
|
Trackback
OpenID
Please login with either your
OpenID
above, or your details below.
Name
E-mail
Home page
Remember Me
Comment (HTML not allowed)
Enter the code shown (prevents robots):
Live Comment Preview