Проблема в том, что вы думаете, AppHolder.Processor
будет каждый раз одним и тем же объектом, но на самом деле это каждый раз новый MailboxProcessor. Я изменил ваш код AppHolder на следующий:
[<AbstractClass; Sealed>]
type AppHolder private () =
static member private Processor =
printfn "Starting..."
Agent.Start(fun inbox ->
let rec loop (s : AppliationState) =
async {
let! action = inbox.Receive()
let s' = s.HandleAction action
printfn "{s: %A s': %A}" s s'
return! loop s'
}
loop AppliationState.Default)
static member HandleAction (action:obj) =
AppHolder.Processor.Post action
Единственное, что я сделал, - это упростил вызов Console.WriteLine для использования printfn
и %A
, чтобы получить больше подробностей отладки, и добавил один вызов printfn "Starting..."
, который будет выполнен непосредственно перед сборкой MailboxProcessor и началось. И результат, который я получил, был:
Starting...
Starting...
Starting...
Starting...
{s: {Store = [];} s': {Store = ["b"];}}
{s: {Store = [];} s': {Store = ["d"];}}
{s: {Store = [];} s': {Store = ["c"];}}
{s: {Store = [];} s': {Store = ["a"];}}
Обратите внимание, что строка printfn "Starting..."
была выполнена четыре раза.
Это ловит много новичков в F #: ключевое слово member
определяет свойство , а не поле. Каждый раз, когда вы оцениваете свойство, тело этого свойства оценивается заново. Поэтому каждый раз, когда вы получаете доступ к AppHolder.Processor
, вы получаете новый MailboxProcessor. Подробнее см. https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/members/properties.
То, что вы, вероятно, хотели, было следующее:
[<AbstractClass; Sealed>]
type AppHolder private () =
static let processor =
printfn "Starting..."
Agent.Start(fun inbox ->
// ...
)
static member HandleAction (action:obj) =
processor.Post action