为什么F#closures可序列化?

时间:2015-03-15 15:55:31

标签: serialization f# f#-3.1

为什么F#闭包具有[<Serializable>]属性?什么是实际用例?

此代码演示了对闭包进行序列化和反序列化:

open System
open System.IO
open System.Runtime.Serialization.Formatters.Binary

let formatter = BinaryFormatter ()
let addTwo = (+) 2

(addTwo.GetType ()).GetCustomAttributes false
|> Array.iter (fun attribute -> 
    printfn "Closure has attribute: %s" (attribute.GetType ()).Name
)

let serializedClosure =
    use memStream = new MemoryStream ()
    formatter.Serialize (memStream, addTwo)
    memStream.ToArray ()

Array.length serializedClosure
|> printfn "Serialized closure length: %d bytes"

let deserializedClosure =
    use memStream = new MemoryStream (serializedClosure)
    formatter.Deserialize memStream :?> Int32 -> Int32

deserializedClosure 3
|> printfn "Invoking deserialized closure: 2 + 3 = %d"

printfn "Press any key to exit..."
Console.ReadKey true |> ignore

这是有效的,因为闭包被编译成一个类(注意serializable关键字:

.class nested assembly auto ansi serializable beforefieldinit addTwo@6
    extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, int32>
{
    .method assembly specialname rtspecialname instance void .ctor () cil managed {...}
    .method public strict virtual instance int32 Invoke (int32 y) cil managed {...}
}

由于闭包名称(如addTwo@6)完全依赖于编译器,即使在稍微修改代码时也会发生变化,我想知道将闭包序列化的原理是什么?

1 个答案:

答案 0 :(得分:1)

我认为答案是将班级标记为serializable没有任何负面影响,可以安全地忽略它。不将类标记为serializable将使其无法序列化(如果有人发现它很好用)。因此,编译器只是选择了一个可能更有用的默认值。

这有什么实际用途吗?好吧,如果您在多台计算机上运行相同的二进制文件并使用二进制序列化相互通信,那么可以以这种方式实际传递函数。我认为没有人真正这样做(MBrace使用更复杂的机制),但它可能是一个选项(或者,当二进制.NET序列化很酷时它会是一个选项: - ))。