如何从覆盖方法中的计算表达式调用基本 F# 方法?
这是这个令人惊讶的问题的一些人为例子。不要问我为什么需要这个特定的场景,实际用例更有意义,但很难表示。特别是,async无关紧要,在实际情况下,我使用不同的计算表达式,甚至不需要 bang ( !) 来调用基本方法。但症状是一样的。
// Base class with a virtual method
type T1 () =
abstract Test : unit -> Async<unit>
default _.Test () =
async {
printfn "In test"
}
// Derived class with an overridden method calling the base in a computation expression
type T2 () =
inherit T1 ()
override _.Test () =
async {
do! base.Test ()
}
let t2 = T2 ()
t2.Test () |> Async.RunSynchronously
Run Code Online (Sandbox Code Playgroud)
上面的代码无法编译:
error FS0405: A protected member is called or 'base' is being used. This is
only allowed in the direct implementation of members since they could
escape their object scope.
Run Code Online (Sandbox Code Playgroud)
这个神秘的消息是什么意思?我从它的直接实现中调用一个公共成员,就像编译器“想要”一样。
那么主要问题是,在这种情况下如何调用基本方法?什么是惯用的 F# 方式?
解决方法是可能的,例如:
error FS0405: A protected member is called or 'base' is being used. This is
only allowed in the direct implementation of members since they could
escape their object scope.
Run Code Online (Sandbox Code Playgroud)
我并不是真的在寻找解决方法,但看到其他人会很有趣。
这里的问题是里面的代码async被编译成一个单独的类,然后它存在于当前类之外,因此它不能以典型的方式调用基本方法。
在这种情况下,您可以在async块之前调用该方法。这是有效的,因为这只是普通方法体的一部分。该方法返回async,直到您调用它时才实际执行do!
type T2 () =
inherit T1 ()
override __.Test () =
let baseTest = base.Test ()
async {
do! baseTest
}
Run Code Online (Sandbox Code Playgroud)
这是一个不错但有限的技巧。当您需要首先计算一些参数然后将它们传递给Test(因为您无法创建baseTest函数 - 它必须是一个值)时,它将不起作用。在这种情况下,唯一的选择是定义一个调用基本方法的辅助方法:
type T2 () =
inherit T1 ()
member private x.BaseTest() =
base.Test ()
override x.Test () =
async {
do! x.BaseTest()
}
Run Code Online (Sandbox Code Playgroud)
我认为这比您的解决方法好一些,因为它不需要基类中的任何虚拟方法。base.Testcall 将从派生类的私有方法中工作。