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

col*_*ang 3 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.
Run Code Online (Sandbox Code Playgroud)

我想DoSomething在继承的对象实例化期间调用一次.但在这里我不被允许.那我该怎么办?

我是否必须创建一个方法

     member this.DoSomething() = base.Param.DoSomething()
Run Code Online (Sandbox Code Playgroud)

并在构造函数中调用它?

type MyInherited() as self =
    inherit MyBase()
    do
         self.DoSomething()
Run Code Online (Sandbox Code Playgroud)

感觉有点怪异,并且重复

更新

我最初的简化示例不合适.检查以下内容:

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
Run Code Online (Sandbox Code Playgroud)

现在实际上它好多了,我需要做的就是使用self而不是base......(我不需要重新定义,Param因为它已经被继承了.)

这里解释了F#有这种限制的原因:

为什么基地只能在私人会员中使用?

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

sgt*_*gtz 6

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

这有效:

do 
  this.DoSomething()
member this.DoSomething() = base.DoSomething() 
Run Code Online (Sandbox Code Playgroud)

但这可以避免像你提到的重复:

do 
  base.DoSomething()
Run Code Online (Sandbox Code Playgroud)

这就是绊倒你的东西 - 构造函数不能有返回值.如果序列中的最后一个语句有返回,则F#假定该函数返回该值/类型的任何值.但是,如果明确定义,这不能与方法签名相反.所以F#要求你在这种情况下明确你的意图.如果你打算抛弃base.DoSomething()的返回,请使用管道到忽略运算符组合|> 忽略如下:

do
  base.DoSomething() |> ignore
Run Code Online (Sandbox Code Playgroud)

让我们换个说法,如果一个功能的宗旨无副作用返回一个值,而如果结果不使用这个值,那么我们可以有把握地断定该功能不需要在构造函数中调用.因此,编译器/交互式环境会向您发出警告.这就是F#在这里所鼓励的.

说句公道话,这不是很明显,除非你采取以下考虑:DO 编译所有这样的陈述到主构造.如果检查F#OO样式的构造函数重载,单元*签名的来源可能更清楚.

通常情况下,隐含定义的返回值会使编写函数变得更加流畅......正如Rich Hickey所说的那样,它现在只是熟悉了.

  • 其他语言单位的另一个名称无效

更新

可能是一种编译器约束正在以过度的方式应用,或者可能是幕后的do被定义为闭包之前被解开并由编译器应用于构造函数.闭包可以看到这个,但是方法/构造函数得到了这个 和一个 基础.这不是很直观吗?看起来你已经找到了需要打磨的粗糙边缘.请考虑提出功能请求.F#现在是完全开源的,因此值得记录这样的案例.

我做了一个简短的练习.虽然可以在构造函数中使用,但是当有覆盖时这是不够的.我认为以下可能是一个不错的前进方向(参见最后的new()块).

[<AbstractClass>]
type MyBase()  =
    let letValue = "let value"
    abstract Method : unit -> string
    default this.Method() = "test"
    member this.Method2() = "Param2"

type MyInherited(param : string) as this =
    inherit MyBase()

    // let localLetValue() = this.letValue      // fails.  let values are private members

    do
      //(fun () -> base.Param) () |> ignore     // Error: The 'base' keyword is used in an invalid way. Base calls cannot be used in closures. Consider using a private member to make base calls.  
      (fun () -> this.Method) () |> ignore       // succeeds -- takes local
      (fun () -> this.base_Method) () |> ignore  // succeeds -- takes base
      (fun () -> this.Method2) () |> ignore      // succeeds -- takes base

    override this.Method() = "ABCdefHIJ"
    member this.base_Method() = base.Method()

    new() as this =
      let a = base.Method()                     // succeeds
      let b = this.Method()                     // succeeds
      MyInherited("some value")
Run Code Online (Sandbox Code Playgroud)