我可以多态访问静态方法



我需要调用类before的静态成员调用类构造函数。该类实现接口,我需要(以多态)在after the object is constructed上(polymorthy)拨打同一静态成员。

我相信某些语言允许一种语言在点之前使用实例名称访问静态方法,例如

myClassInstance.staticMethod

f#似乎不允许这样做,尤其是当类从接口继承的情况下,因为接口不能包含静态方法。

以下代码例证了问题:

module Types
type IMult =
    abstract member Something : float
    abstract member MultBy : float -> float
open Types
type Point(x: float) =
    interface Types.IMult with
        member this.Something with get() = x
        member this.MultBy (x: float) =
            (this :> IMult).Something * x
    static member public foo x = x + 3.0
let myPointConstructorArgument = Point.foo 5.0
let pt = Point(myPointConstructorArgument)
printfn "%f" <| (pt :> IMult).MultBy 10.0 // OK: 80.0
let bar (instnc: IMult) = instnc.foo // Error: foo not defined 
let pt0 = Point(bar pt 6.0) // No good: error above

我的问题是:是否可以以某种方式检索对象的类,然后调用抽象方法?

我尝试了以下内容:

let ptType = pt0.GetType()
let mtd = ptType.foo // Error: foo not defined
let mtd = ptType.GetMethod("foo") // Ok, but not what I need, see below
let i2 = mtd 3.0 // Error: mtd is not a function

有关此操作的替代方法的任何建议?

听起来您真正想要的是"类型类"或"证人",这是尚不支持的语言功能,但是此问题,跟踪该功能的实现非常活跃。
目前在F#中有几种获得您想要的多态性访问的方法。

1)通过接口实例成员。看来您不能将多态构件直接放在IMult类型上,因为您需要在构造实例之前访问它,但是您可以为"类型" 创建界面,然后将其传递给作为另一个参数(这与类型类在"封面下"的工作非常相似):

//your "trait"
type IFoo<'a> =
  abstract member Foo : float -> float
//your "witness", defines what "Foo" means for the "Point" type.  Other witnesses could define what "Foo" means for other types.
let fooablePoint = { new IFoo<Point> with member this.Foo x = Point.foo x }
let bar (fooable:IFoo<'a>) = fooable.Foo //this isn't really necessary anymore, but illustrates that a function can use a polymorphic "static" function, given a witness
let pt0 = Point(bar fooablePoint 6.0)

2)静态成员约束(如上所述所指出):

let inline bar (pt:^a) x = 
  (^a : (static member foo : float -> float) x)

一方面,这使您能够在类型上访问静态成员,尽管不应根据fsharp.org过度使用它。它的语法非常不透明,很难破译。此外,它仅适用于内联函数,因此,如果使用普遍存在,可能会大大破坏应用程序的性能。请注意,这也只有在您已经具有^a类型的实例时才有效,因此此解决方案也可能对您不起作用。

3)只需将foo函数传递到其他需要的其他功能中:

let bar (foo:float -> float) x = foo x // type annotations wouldn't be necessary, and just provided for clarity
let pt0 = Point (bar Point.foo 6.0)

4)(在下面的评论中讨论):内部IMult您仍然可以定义

abstract member foo: float -> float 

然后在Point中,只有

interface Types.IMult with 
  member this.Foo x = Point.foo x

这可能会给您您想要的一切。然后,该成员将在Point类型( and IMult上的实例成员)上以静态成员的形式存在,因此它不再是"静态多态性",但它可能会实现您的目标。

我会选择上面的" 1",不要挂在类型的类别上 - 它们不存在,在某些方面,它们并不理想。<<

对我而言,您缺少抽象,将其视为某种工厂或域实体,可以捕获您的静态方法,并只是明确地将其传递。

type MultDomain<'a when 'a :> IMult> =
    abstract member foo :  float -> float
type PointDomain =
    interface MultDomain<Point> with
        member o.foo x = x + 3.0

(在您的上下文中不需要约束" a:> imult",但表明您可以在此接口中使用您尚未创建的对象的类型)

所以答案是"是的,只要您将它们映射到某种类型的实例方法,您可以用多态词法调用" ...或者也许"不,但是您可以将它们映射到某种类型的实例方法。

(我个人从来没有静态方法,甚至避免构造函数!)

最新更新