Почему замыкания 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-сериализация была классной:-)).

Другие вопросы по тегам