属性 'Context' 是 F# 中的静态错误

Property 'Context' is static error in F#

我在将 Akka.Net actor 从 C# 重写为 F# 时遇到问题:

public class Listener : ReceiveActor
{
    public Listener()
    {
        Receive<Messages.Shutdown>(s =>
        {
            Console.WriteLine($"shutdown {s.Duration}");
            Context.System.Terminate();
        });
    }
}

Actor 应该通过终止 Actor 系统来处理关闭消息。我试着像这样重新实现它:

type Listener() =
    inherit ReceiveActor()
    do
        base.Receive<Messages>(fun m -> 
            match m with 
            | Shutdown(duration) -> 
                printf "shutdown %s" (duration.ToString())
                base.Context.System.Terminate()
                true
            | _ -> false)

但第 base.Context.System.Terminate() 行出现编译错误 Property 'Context' is static。这段代码有什么问题?为什么我不能访问基类的静态 属性?是不是因为这段代码在 lambda 表达式中(有趣)?还是因为它在构造函数中(做)?

你可以这样写:

type Listener() =
    inherit ReceiveActor()
    do
        base.Receive<Messages>(fun m -> 
            match m with 
            | Shutdown(duration) -> 
                printf "shutdown %s" (duration.ToString())
                ReceiveActor.Context.System.Terminate()
                true
            | _ -> false)

注意这里可以用function代替match ...with:

        base.Receive<Messages>(function 
            | Shutdown(duration) -> 

那么 printfn 相当于 WriteLine 和这个:

printfn "shutdown %s" (duration.ToString())

等同于:

printfn "shutdown %O" duration

更新

如果它是静态的 属性,如您的错误消息所述,您不能从 lambda 中使用它,对于该问题,请参阅 this 已回答的问题。

想通了。问题是:

  1. 我使用了错误的语法来访问基 class 的静态成员。正如@ildjarn 评论的那样,它应该是 ReceiveActor.Context,而不是 base.Context

  2. 无法从 lambda 表达式访问受保护的成员。处理程序需要是成员方法。

工作版本:

type Listener() as this =
    inherit ReceiveActor()
    do
        base.Receive<Messages>(this.handle)

    member this.handle(message: Messages): bool = 
        match message with 
        | Shutdown(duration) -> 
            printf "shutdown %s" (duration.ToString())
            ReceiveActor.Context.System.Terminate()
            true
        | _ -> false

重要更改:1. as this 允许我们从构造函数调用成员方法,2. 编译器需要 handle 方法中的类型注释来解决 Receive 方法重载歧义。