gpt4 book ai didi

f# - 从代码引用中调用基类方法

转载 作者:行者123 更新时间:2023-12-05 00:21:05 25 4
gpt4 key购买 nike

假设我有两个简单的类:

type BaseClass() =
abstract member PreStart : unit -> unit
default x.PreStart() =
printfn "Base class PreStart method"

type DerivedClass() as this =
inherit BaseClass()

override this.PreStart() =
// I want to pass the body from outside
()

我想要做的是允许一个可以通过 DerivedClass.PreStart 的实现主体的场景。从外面的方法。当然,我可以只传递一个可以在 PreStart 中调用的函数。方法,但这有一些与调用 base.PreStart() 相关的缺点方法。我必须传递一个额外的参数来指示我想要在覆盖主体之前或之后执行基本方法的任何内容。

我想做的是允许这样定义 body :
let preStart = (fun (baseFn : unit->unit) ->
baseFn() // base class call before the overriden body
printfn "PreStart overriden"
baseFn() // base class call after the overriden body)

在哪里 baseFn()是对基类方法的调用。如果我们可以将委托(delegate)传递给 base.PreStart,这将很简单。调用,但由于明显的原因,编译器不允许这样做。

我对报价单的天真实现如下:
open FSharp.Quotations
open Microsoft.FSharp.Linq
open Microsoft.FSharp.Linq.QuotationEvaluation
open System.Linq.Expressions

type BaseClass() =

abstract member PreStart : unit -> unit

default x.PreStart() =
printfn "Base class PreStart method"

type DerivedClass(expression : Expr<(unit -> obj) -> obj>) as this =
inherit BaseClass()

// this is not optimal <@@ this :> BaseClass @@> doesn't work
let baseClinst = new BaseClass()
let bexpr = <@@ baseClinst @@>
let overrideExpr = expression
let baseTy = typeof<BaseClass>
let mthd = baseTy.GetMethod("PreStart")

override this.PreStart() =
let baseMthd = Expr.Call(bexpr, mthd, [])
let combined = <@ ((%overrideExpr) (baseMthd.CompileUntyped())) @>
let l = QuotationEvaluator.EvaluateUntyped combined
()

let preStart = <@
fun (baseFn : unit->obj) ->
baseFn() // base class call before the overriden body
printfn "PreStart overriden"
baseFn() // base class call after the overriden body
@>

let d = new DerivedClass(preStart)

如果按预期打印以下输出:
> d.PreStart();;
Base class PreStart method
PreStart overriden
Base class PreStart method
val it : unit = ()
>

但是我对这段代码不满意
  • DerivedClass我必须创建一个基类的实例 let baseClinst = new BaseClass()用作 Expr.Call 的基本表达式参数.这样做不起作用let bexpr = <@@ this :> BaseClass @@> .这只是调用反射检索到的另一个基类实例。
  • 我不得不从 unit -> unit 修改函数的类型至unit -> obj因为对 baseMthd.CompileUntyped() 的调用返回
  • 它当然不是最优的和丑陋的。

  • 我的问题很简单。如何将此代码改进为更惯用的 F#?或者也许除了报价之外还有其他方法可以实现它?

    最佳答案

    你真的不需要报价。显而易见的解决方案(不起作用)是获取一个函数并传递它base.PreStart作为参数(以便函数可以决定何时调用基类实现):

    type DerivedClass1(preStart) =
    inherit BaseClass()
    override this.PreStart() =
    preStart base.PreStart

    现在,这不起作用,因为 F# 只允许您调用 base.PreStart直接,它不允许将其作为函数传递。但是,您可以定义一个私有(private)的 member调用基类实现并将这个新成员作为参数传递给 prestart :
    type DerivedClass(preStart) =
    inherit BaseClass()
    member private this.BasePreStart() =
    base.PreStart()
    override this.PreStart() =
    preStart this.BasePreStart

    关于f# - 从代码引用中调用基类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32255014/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com