F# techniques
F# users can enjoy a superb serialization experience with Nerdbank.MessagePack. Nerdbank.MessagePack's union support includes support for native F# union types, thanks for PolyType's built-in support for them.
The following snippet shows serializing a farm with various animals, converting to JSON for inspection, and deserializing the msgpack back again.
type Animal =
| Cow of name: string * weight: int
| Horse of name: string * speed: int
| Dog of name: string * color: string
type Farm = { Animals: Animal list }
let farm = {
Animals = [
Cow("Bessie", 1500)
Horse("Spirit", 45)
Dog("Rex", "Brown")
]
}
let serializer = MessagePackSerializer()
let msgpack =
let refableValue = farm // need to pass by reference
serializer.Serialize(&refableValue, ReflectionTypeShapeProvider.Default)
MessagePackSerializer.ConvertToJson(msgpack) |> printfn "Farm as JSON: %s"
let newFarm = serializer.Deserialize<Farm>(msgpack, ReflectionTypeShapeProvider.Default)
printfn "Farm animals:"
newFarm.Animals |> Seq.iter (function
| Cow(name, weight) -> printfn "Cow: %s, Weight: %d" name weight
| Horse(name, speed) -> printfn "Horse: %s, Speed: %d" name speed
| Dog(name, color) -> printfn "Dog: %s, Color: %s" name color)
AOT readiness
The above snippet uses the ReflectionTypeShapeProvider which allows a single F# project to work out of the box.
Reflection can be avoided, and an F# program can be AOT-safe by:
- Define your data layer in an F# library project.
- Define a witness type for your F# data types from within a C# project that references your F# data types library.
- Define your F# application that references both your data layer F# project and your C# witness type project. Pass the witness type to any serialize/deserialize method such as Serialize<T, TProvider>(in T?, CancellationToken) and Deserialize<T, TProvider>(ReadOnlyMemory<byte>, CancellationToken)