Почему замыкания F# сериализуемы?
Почему замыкания 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 ответ
Я думаю, что ответ заключается в том, что маркировка класса как serializable
не оказывает негативного влияния и может быть безопасно проигнорировано. Не помечать класс как serializable
сделало бы невозможным сериализацию (если бы кто-то нашел для этого хорошее применение). Таким образом, компилятор просто выбирает более полезное значение по умолчанию.
Есть ли реальное использование для этого? Ну, если у вас один и тот же двоичный файл, запущенный на нескольких машинах и общающийся друг с другом с помощью двоичной сериализации, то вы могли бы фактически передать функции таким образом. Я не думаю, что кто-то на самом деле это делает (MBrace использует более сложный механизм), но это был бы вариант (или вариант, когда двоичная.NET-сериализация была классной:-)).