F# 从继承的类构造函数调用lambda函数中的基成员?

F# 从继承的类构造函数调用lambda函数中的基成员?,f#,F#,我有一个基础班 type MyBase() = let param = myfun() member this.Param = param type MyInherited() = inherit MyBase() do base.Param.DoSomething() // cannot access base in let or do binding. 我想在继承的对象实例化期间调用DoSomethingexact一次。但在这里我是不被

我有一个基础班

type MyBase() =
    let param = myfun()
    member this.Param = param


type MyInherited() =
    inherit MyBase()
    do
         base.Param.DoSomething() // cannot access base in let or do binding.
我想在继承的对象实例化期间调用
DoSomething
exact一次。但在这里我是不被允许的。那我该怎么办

我必须创建一个方法吗

     member this.DoSomething() = base.Param.DoSomething()
并在构造函数中调用它

type MyInherited() as self =
    inherit MyBase()
    do
         self.DoSomething()
感觉有点奇怪,而且是重复的

更新 我最初的简化示例不合适。检查以下各项:

type MyBase() =
    let param = "test"
    member this.Param = param

type MyInherited() =
    inherit MyBase()
    do
       (fun () -> base.Param) () |> ignore  // Doesn't work, 
   // 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.


type MyInherited() as self =
    inherit MyBase()
    do
       (fun () -> self.Param) () |> ignore  // Works
现在实际上它好多了,我所需要做的就是使用
self
而不是
base
。(我不必重新定义
Param
,因为它已经被继承了。)

这里解释了F#具有此类限制的原因:


但是我仍然不清楚为什么不能在闭包中使用
base
,尽管它可以在简单的let绑定中访问。

无法复制。例如,这对我是有效的:

type MyBase() =
    let param = "test"
    let param' = fun _ -> printfn "test'"
    member this.Param = param
    member this.Param' = param'

type MyInherited() =
    inherit MyBase()
    do
       printfn "%s" (base.Param.ToString()) 
       base.Param'()

let inh = new MyInherited()

您的初始代码完全有效。您不必首先定义一个调用基的方法

这项工作:

do 
  this.DoSomething()
member this.DoSomething() = base.DoSomething() 
但这避免了您提到的重复:

do 
  base.DoSomething()
这就是让你绊倒的地方——构造函数不能有返回值。如果序列中的最后一个语句有一个返回,F#假设函数有一个返回值,该值/类型是什么。但是,如果显式定义,这不能与方法签名相反。所以F#要求你在这种情况下明确你的意图。如果您打算放弃base.DoSomething()的返回,请使用管道忽略|>忽略的操作符组合,如下所示:

do
  base.DoSomething() |> ignore
换一种说法,如果函数的目的是返回一个没有副作用的值,并且如果这个值因此没有被使用,那么我们可以安全地得出结论,函数不需要在构造函数中调用。因此,编译器/交互环境会警告您这一点。这正是F#在这里鼓励的

平心而论,除非你考虑到以下几点,否则这并不明显:do。如果您查看F#OO样式,您可能会更清楚地了解单元*签名的来源

通常,隐式定义返回值会使编写函数的过程更加流畅。。。正如里奇·希基所说,现在只是因为熟悉而已

  • 在其他语言中,单位的另一个名称是void

更新 可能是编译器约束被过度应用,或者可能是在后台,do被定义为解绕前的闭包,并由编译器应用于构造函数。闭包可以看到this,但是方法/构造函数会得到this基。这不是很直观,是吗?看起来你发现了一个需要打磨的粗糙边缘。请考虑做一个。F#现在是完全开源的,所以记录这样的案例是值得的

我做了一个简短的练习。虽然可以在构造函数中使用此
,但在存在重写时,这是不够的。我认为下面可能是一个不错的前进方向(请参阅最后的new()块)

[]
类型MyBase()=
let letValue=“let value”
抽象方法:单位->字符串
默认情况下,此方法()为“测试”
成员this.Method2()=“Param2”
键入MyInherited(param:string),如下所示=
继承MyBase()
//让localLetValue()=this.letValue//失败。让值为私有成员
做
//(fun()->base.Param)(|>ignore//Error:“base”关键字的使用方式无效。在闭包中不能使用基调用。考虑使用私有成员进行基本调用。
(fun()->this.Method)(|>ignore//successfuls--获取本地
(fun()->this.base_方法)(|>ignore//successfuls--接受base
(fun()->this.Method2()|>ignore//成功--以
重写此。方法()=“ABCdefHIJ”
成员this.base_Method()=base.Method()
新的()像这样=
设a=base.Method()//成功
设b=this.Method()//成功
我继承的(“某些价值”)
这项工作:

type MyInherited2() =
    inherit MyBase()

    let p = base.Param

    do
        (fun () -> p) () |> ignore
MyInherited示例中的问题是由于在闭包中捕获了
base.Param
。这在let绑定中起作用,因为对于所有意图和目的,对象构造函数中的let绑定都是成员的直接实现


但你是对的,你觉得继承很奇怪。这是F#中的一大罐蠕虫,如果你无法完全避免,最好保持简单

Param属性的类型是什么?DoSomething()的返回值是多少?我不能复述你的情况。这似乎对简单的财产有用谢谢。我之前的问题不是很清楚,我已经更新了。不过,你的回答仍然很有启发性,将来肯定会对我有所帮助。@colinfang:yw。我做了一个更新作为回应。请参阅new()部分。我想这可能是一种得到你想要的东西的方式。
type MyInherited2() =
    inherit MyBase()

    let p = base.Param

    do
        (fun () -> p) () |> ignore